「なぜPHPアプリにセキュリティホールが多いのか?」のセキュリティホール
大垣靖男さんの連載から
第21回 文字エンコーディングとセキュリティ(3):なぜPHPアプリにセキュリティホールが多いのか?|gihyo.jp … 技術評論社
一見この動作は無害のように思えるかもしれませんが,ブラウザなど,“\”がエスケープ文字になっているシステムでは重大な問題となります。
<div height="<?php echo addslashes($height); ?>" width="<?php echo addslashes($width); ?>">
この記事が公開された当初,上記のechoが抜けていた。しかし,echoがないと,プログラムの正常系としても動作しない。どこかから,突っ込みが入ったのであろう,その後echoが追加された。
しかし,まだ根本的におかしい。
なぜなら,以下の部分が間違っているからだ。
ブラウザなど,“\”がエスケープ文字になっているシステム
あいまいな表現だが,上記の文脈では,HTMLのエスケープに「\」を使用するというように読める。しかし,HTMLのエスケープは実体参照や文字参照を用いるので,「\」はエスケープ文字ではないので,先のサンプルは意図通りに動かない。
以下のように,実際に動くPHPスクリプトを作成して試してみた。
<?php
$height = $_GET['h'];
$width = $_GET['w'];
?>
<body>
<div height="<?php echo addslashes($height)?>" width="<?php echo addslashes($width)?>">
</body>
ここで,記事の通り,h=1234表 w=><script>alert(document.cookie)<script> というパラメータを指定しても,スクリプトは起動されない。
この際のHTMLソースは以下のようになる。
<body>
<div height="1234表\" width="><script>alert(document.cookie)</script>">
</body>
height="1234表\" が問題だが,「\」で「"」はエスケープされないので,攻撃は可能とならない。「"」をエスケープする場合は,"を用いるのだ(大垣さんはご存じだろうが)。
方や,h="><script>alert(document.cookie)</script> という,極めてありがちなXSS検査パターンを指定すると,alertが起動される。その際のHTMLソースは以下のようになる。
<body>
<div height="\"><script>alert(document.cookie)</script>" width="">
</body>
なにがいけなかったというと,そもそもaddslashesはXSS対策に使っても無意味であって,文字エンコーディングとは関係ないのだ。すなわち,元のサンプルはごく普通にXSSぜい弱性があっただけだ。
大垣さん,技術評論社という伝統ある出版社のサイトに公開する以上は,せめてチェックしてから公開しましょうよ。
(2010/4/23追記)
久しぶりに元サイトを見ると、修正がなされていた。
alert("1234表\" + "さんは" + "悪意のあるデータ ……
しかし、この「悪意のあるデータ」は実行されない。「表」の後の「\"」がダブルクォートをエスケープしたものとなるが、その後の「"」で文字列リテラルが終端され、「さんは」以降がJavaScriptの式として認識されるが、このような構文はないので、JavaScriptのシンタックスエラーになるからだ。「せめてチェックしてから公開しましょう」という忠告は、聞いてもらえてないようで残念だ。