|
CGIの利用ユーザが送信したデータを受け取る際の処理方法について考えてみます。
ここでは掲示板のCGIを作成するとして受け取ったデータはデコード処理を終えて投稿者名($name)、メールアドレス($mail)、URL($url)、コメント($cmnt)に格納されているものとします。
|
|
■XSS(クロスサイトスクリプティング)
CGIプログラムでは主に、ユーザが入力したデータを処理し、その結果をブラウザに表示します。
ブラウザではHTMLだけではなくスクリプト(JavaScriptやVBscriptなど)を実行させる事が出来ます。
ユーザが入力したデータをそのままブラウザに表示してしまうとXSSという方法を用いて外部スクリプトを起動し、クッキーに記録されているショッピングサイト等で使用しているアカウント情報などを盗まれたりする場合があります。
|
|
■サニタイズ処理
ユーザが入力したデータを無害化する処理の事です。
<(開始タグ)と>(終了タグ)をそれぞれ<と>に置換する事で<script>タグをはじめ、その他全てのタグを無効にします。
また、その他の歓迎されない文字についても無効化を行います。
このサニタイズ処理はCGIプログラムで受け取るデータ全てに行う必要があります。
|
|
$name = &sanitize($name);
$mail = &sanitize($mail);
$url = &sanitize($url);
$cmnt = &sanitize($cmnt);
sub sanitize {
$_[0] =~ s/&/&/g;
$_[0] =~ s/"/"/g;
$_[0] =~ s/'/'/g;
$_[0] =~ s/</</g;
$_[0] =~ s/>/>/g;
return($_[0]);
}
|
|
□&を置換
ブラウザは&に続くコードにより対応文字に変換して表示しますので&を&自身のコードである&に置換する事でこれを抑制します。
|
|
□"と'を置換
ユーザが入力したデータ内にダブルクオートやシングルクオートが含まれているとCGIプログラム処理中のエラーや処理後のHTML出力時にスタイル崩れが発生する場合がありますのでそれぞれのコードに置換しておきます。
|
|
■擬似スキームの排除
サニタイズ処理を行う事で殆どのXSSを防ぐ事が出来ますが完全ではありません。
ユーザがURLとして入力したデータが擬似スキームを行うコードであった場合、これを<a>タグや<img>タグなどのURLの属性部にそのまま指定するとスクリプトが起動されてしまいます。
これを防ぐにはURLの書式でないデータの場合は<a>タグや<img>タグでリンクしないようにします。
メールアドレスを<a>タグでリンクする場合は書式を簡易チェック後に行います。
|
|
if ($url =~ /^(https?|ftp):\/\/[\w\.\-\/\~]+$/) {
print "<a href=\"$url\">HomePage</a>\n";
}
|
|
if ($mail =~ /^.+\@.+\..+$/) {
print "<a href=\"mailto:$mail\">Mail</a>\n";
}
|
|
|
URLとして使用出来る記号は他にもありますが上記の例では一般的なURLが入力された場合のみリンクしています。
これにより?に続くCGIのクエリ送信起動や%を使用したエンコードURLを排除する事が出来ます。
|
|
■イベントハンドラの排除
HTMLタグ内の属性部にユーザが入力したデータを埋め込む場合はダブルクオートまたはシングルクオートを必ず使用します。
こうする事により、イベントハンドラの実行を無効化する事が出来ます。
|
|
print "<img src=$url>\n"; → ×
print "<img src=\"$url\">\n"; → ○
|
|
|
<textarea name="cmnt"></textarea>
|
|
|
上記のフォームに入力されるデータは改行を含む場合があります。
改行を含むデータをログファイルに記録するとログファイル内で改行されてしまい不具合が起きますので<br />タグなどに置換後、記録します。
|
|
$cmnt =~ s/\r\n/<br \/>/g;
$cmnt =~ s/\r/<br \/>/g;
$cmnt =~ s/\n/<br \/>/g;
|
|
|
\r\n(CrLf)はWindows既定の改行コード、\r(Cr)はMac既定の改行コード、\n(Lf)はUNIX既定の改行コードです。
これらを全て<br />タグに置換しています。
|
|
<input type="text" name="name" />
<input type="password" name="pass" />
|
|
|
上記のフォームに入力されるデータは通常の場合は改行を含む事はありません。
しかし携帯端末などに採用されているブラウザでは上記のフォームへの入力時に普通に改行する事が出来る場合があります。
また、フォームを介さずに改行コードをスクリプトに直接送信する事も出来ますので改行コードを削除する等の対策を行う事が必要です。
|
|
$name =~ s/\r\n//g;
$name =~ s/\r//g;
$name =~ s/\n//g;
$pass =~ s/\r\n//g;
$pass =~ s/\r//g;
$pass =~ s/\n//g;
または
$name =~ s/[\r\n]//g;
$pass =~ s/[\r\n]//g;
|
|
■最後に
当ページで解説した内容は1つの提案に過ぎません。
XSSや不正アクセスの事について勉強しCGIで受け取るデータの処理方法について独自のルールを作成してみましょう。
|
|
□更新履歴
2007.04.27 全体的に内容を見直し
2005.12.30 補足(改行の取り扱い)を追加
|
|
|