「なぜ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表\" が問題だが,「\」で「"」はエスケープされないので,攻撃は可能とならない。「"」をエスケープする場合は,&quot;を用いるのだ(大垣さんはご存じだろうが)。

方や,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シンタックスエラーになるからだ。「せめてチェックしてから公開しましょう」という忠告は、聞いてもらえてないようで残念だ。