Perl を使って簡単、クライアント/サーバ作っちゃうメモ(2002/11/11) 
  

クライアント作る!

実は、結構簡単だったりします。クライアント側はデータを送り込むだけなんです。ただデータの送信がGET/POSTの違いなだけです。といってもGETって?POSTって?ってところから。

プログラムから・・・・

<html>
<head>
<title>CGIサーバ接続テストプログラム</title>
</head>
<body>
<h1>CGIサーバ接続テストプログラム(POST形式)</h1>
<form action="http://localhost/cgi-bin/form_srv.cgi" method=post>
ID
<input type="text" name="ID" value="murachi" size="30" maxlength="8"><br>
PASSWORD
<input type="text" name="PASSWORD" value="12345678" size="30" maxlength="8"><br>
<input type="submit" value="POSTで送信">
</form>
<h1>CGIサーバ接続テストプログラム(GET形式)</h1>
<form action="http://localhost/cgi-bin/form_srv.cgi" method=get>
ID
<input type="text" name="ID" value="murachi" size="30" maxlength="8"><br>
PASSWORD
<input type="text" name="PASSWORD" value="12345678" size="30" maxlength="8"><br>
<input type="submit" value="GETで送信">
</form>
</body>
</html>

GET形式は「http://localhost/cgi-bin/form_srv.cgi?LOGIN=murachi&PASSWORD=12345678」と送信データがURLの後ろに付いているのが特徴で、簡単にデータをやりとりすることが可能です。但し簡単な反面、大量のデータを送信できない(最大255Byte)ことや、送信データが丸見えになっているためセキュリティや悪質な悪戯などされてしまう可能性が大きい点があげられます。

POST形式は、大量のデータを送信するのに向いており、しかも送信データをある程度、隠蔽することができます。HTML上から GET形式との違いを見出せませんが、http プロトコルを使用しデータを送受信する場合には、大きな違いがあり苦労することとなります。

サーバを作る!

実は、こちらも結構簡単だったりします。サーバ側の作りは、下記の様に大まかに4つの段階に分かれており、結果的に処理結果を1クライアント側から送られたデータを受け取り処理結果を返す事だけとなります。

【その1】 クライアントからGET/POSTデータ読み込む点です。GET/POST形式で送信された情報は、環境変数 REQUEST_METHOD に、GET/POST の文字列が設定されているので、GET=環境変数 QUERY_STRING、POST=ストリーム(STDIN)からデータを読み込みます。

【その2】取り込んだデータを見ると、特殊な構造となっていることが判りますので、まずこのデータを "&" で分解し、その後 "=" で分解する作業となります。またデータはURLエンコードされているため、そのデータをデコード化処理する必要があります。

【その3】データから実処理を行います。

【その4】実処理を行った結果をクライアントに返します。通常は結果をHTMLとして返しますが、Perlテンプレートライブラリを使うと非常に便利です。

上記の段階をプログラムすると下記の様になります。

【その1】

if ($ENV{"REQUEST_METHOD"} eq "POST") {
    read (STDIN, $data, $ENV{"CONTENT_LENGTH"});
} elsif ($ENV{"REQUEST_METHOD"} eq "GET") {
    $data = $ENV{'QUERY_STRING'};
}

【その2】

# "&" の区切りで分解し、配列に代入
@values = split (/&/, $data);

# "=" の区切りで分解し、連想配列に代入
for (@values) {
    ($name,$value)=split /=/;
    $values{$name}=$value;
}

# データ部分をURLデコードし元のデータに復元
for (sort keys %values){
    $values{$_} =~ tr/+/ /;
    $values{$_} =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
}

【その3】こんな簡単な処理

# ちょっとした処理(受け取ったデータを、他の連想配列に設定しているだけ)
%ret = ("ID" => $values{ID},
          "PASSWORD" => $values{PASSWORD}
);

【その4】

print "Content-type: text/html\n\n";
print <<END_of_Multiline_Text;
<META HTTP-EQUIV="Content-Type" CONTENT="text/html;charset=x-sjis">
</HEAD><BODY>
<FORM METHOD="POST" ACTION="/cgi-bin/hoge.cgi">
<B><FONT SIZE=3>INPUT FORM<P>
ID<INPUT TYPE="TEXT" NAME="ID" SIZE=8 LENGTH=8 VALUE="$ret{ID}"><P>
PASSWORD<INPUT TYPE="TEXT" NAME="PASSWORD" SIZE=8 LENGTH=8 VALUE="$ret{PASSWORD}"><P>
</B>
</FONT>
<INPUT TYPE="submit" VALUE="COMMIT"><INPUT TYPE="reset" VALUE="Clear">
</FORM>
</BODY></HTML>
END_of_Multiline_Text

  参考 : futomi's CGI Cafe-入力フォーム編(GETとPOSTを受け取るには)

  参考 : Perl と CGI入門

 

 

そのた!

コメント欄とか入力欄から入力された文字列をそのまま使用すると、「クロスサイトスクリプティング」というセキュリティホールになります。これは簡単に説明すると、例えばアンケート入力フォームで入力した内容を、次の画面で確認する様なフォームを使用した場合、通常入力した文字列をそのまま表示しようとします。ここで問題が発生します。

なにが問題かと言うと、入力文字列を前のHTMLから受け取り、動的にHTMLを作成するため入力された文字列にHTML文法が記述されていると、それが実行されてしまうという事なのです。詳しくはここを参照

ですので対処として。入力された文字列の中にあるHTML文法を、無効化してしまう事により対処できます。他にも色々考慮することは、沢山ありますがねぇ・・・・

my $input = $_[0];
$input =~ s/\x0D\x0A/<BR>/g; # Windows の改行
$input =~ s/\x0D/<BR>/g; # UNIX系 の改行
$input =~ s/\x0A/<BR>/g; # MacOS の改行
$input =~ s/&/&amp;/g; # & → &amp;
$input =~ s/</&lt;/g; # < → &lt;
$input =~ s/>/&gt;/g; # > → &gt;
$input =~ s/"/&quot;/g; # " → &quot;
$input =~ s/'/&#39;/g; # ' → &#39;
$input =~ s/\"/&quot;/g; # " → &quot;

その他に考えることは・・・・「機種依存文字のチェック」、「半角かな」、「漢字コード」。。。。