[PHP-users 8359] Re: 簡易クロスサイトスクリプティング対策スクリプト

Yasuo Ohgaki php-users@php.gr.jp
Mon, 01 Jul 2002 13:22:49 +0900


大垣です。

Masaru Matsunami wrote:
> わたしがまとめた情報がこちらにあります。
> 「クロスサイトスクリプティング」
> http://www.ipa.go.jp/security/awareness/vendor/programming/a01_02.html
> 
> ※ウソなど書いていましたらご指摘頂ければと思います。

Java, Perl, ASPがあってPHPの項目がない事が残念で
すが、安全なWebサイト作りのキーポイントは説明してある
と思います。

sessionは不必要にクライアント側のファイルシステムに
保存せず、session cookie(ブラウザ終了時に削除され
るcookie)を使った方がよい、比較的安全なログインの実装、
比較的安全または安全な自動再ログインの実装方法など、
細かい事を説明しだすと本になってしまうのでこのくらいの
ボリュームでまとまっていると非常に便利でよいと思います。

間違いを見つけた訳ではありませんが、説明されていると
良いのではと思う項目があります。

初心者だけでなく、経験のあるプログラマでも型の取り
扱いが厳しい言語からloosely typed/type less
言語に乗り換えたばかりのプログラマの場合を以下の
ようなミスをする事も多いと思います。

数値の比較について以下の様な例があると危険性を理解
しやすいのでは、と思っています。

=====bad_script.php======
<html>
<head>
<title>Bad Script</title>
</html>
<body>
<h1>BAD SCRIPT</h1>
<form>
<input type="radio" name="radio_val" value="1">選択肢1</input>
<input type="radio" name="radio_val" value="2">選択肢2</input>
<input type="radio" name="radio_val" value="3">選択肢3</input>
<input type="submit">
</form>
<br />
<br />
<?php
if (!isset($_GET['radio_val']))
  $_GET['radio_val'] = 1;

if (1 <= $_GET['radio_val'] && $_GET['radio_val'] <= 3) {
  echo 'Value is Ok: '.$_GET['radio_val'];
}
else {
  echo 'Value is dangerous';
}

echo "<br>";
echo htmlentities($_GET['radio_val']);

?>
</body>
</html>
========

なぜ、このコードが悪いか確認されたい方はファイルに保存して
http://example.com/bad_script.php?radio_val=3%3Cscript%20language=%22javascript%22%3Ealert('Your%20site%20is%20bad')%3C/script%3E
のようなリクエストを送信すると悪意のあるサイトはセッション
情報ID等を取得可能である事が解ります。(cookie等を盗むに
はスクリプトの中身を変更する必要があります)

strspn()、is_*()、正規表現、キャスト、配列を利用した確認
などを行なわないと思わぬ(?)副作用があるので注意が必要と思
います。

# 個人的にはこのような選択項目チェックミスの方が
# 多いのでは?と思っています。

PHPだけでなく連想配列をサポートする言語を使われている場合、
固定的な選択項目は以下の様なスクリプトで簡単にチェックする事
ができるので、必ずチェックするベキと思います。

$vals_expected = array('item1', 'item2', 'item3');
if (in_array($_GET['val'],$vals_expected, true) {
 // Ok to go
}
else {
 // NOT ok to go
}

PHPの場合、選択値に日本語等を含まないければ連想配列のキーを
利用した方が格段に早くなります。値が英数字の場合は

$vals_expected = array('item1'=>1, 'item2'=>1, 'item3'=>1);
if (isset($vals_expected[$_GET['val']])) {
  // OK
}
else {
  // NG
}

とする方が良いです。

--
Yasuo Ohgaki