ジュンク堂本店の「PHP」コーナーで一番目に付く位置に飾られていた本を読 んでみた。
帯の宣伝文句はこうだ。
PHP5で作るWebアプリケーション
待望の改訂版登場!
最新機能まで踏み込んだ内容と、必要な環境を収録したCD-ROMで、着実に学ぶ
着実に……ですか。
最初の動くサンプルコードはこうなっている(p.72)。
<html> <head><title>hello_world.php</title></head> <body> <?php $var_str="Hello World"; print ($var_str); ?> </body> </html>
ここは教育上、次のように教えるべきだ。
<?php $var_str = "Hello World"; print(htmlspecialchars($var_str)); ?>
HTMLを出力しているのだから当然にhtmlspecialchars()を入れる。 (セキュリティどうこういう説明はここでは不要。)
$_GET ないし $_POST を使う最初のサンプルはこうなっている。 (3.1節「サーバーとクライアント間のデータのやりとり」p.151)
<?php $name = $_POST['name']; print("次のデータを受け取りました<br />"); print("名前:".$name."<br />"); ?>
クロスサイトスクリプティング脆弱性だ。ずっとこんな調子でサンプルコード が続く。
3.3節「ファイルを扱う」にこんな記述がある。(p.159)
$updirにアップロード場所を代入しています。「./upload/」の「.」はカレン トディレクトリのことで、通常このPHPスクリプトが置いてあるディレクトリ を指します。アップロードディレクトリはフルパスで指定しても構いませんが、 通常はセキュリティ・可搬性を考え、相対パスで指定しま す。フルパスでは、スクリプトの置き場所を変えた際に、書き換えが 必要になります。
「ファイル丸見え漏洩」を起こす糞CGIプログラムの製造を助長する記述だ。 こういう糞解説は2002年に絶滅したと思っていたが……。 セキュリティのことを考えれば、絶対パス名で置き場所を指定するようにし、 スクリプトを設置する者が安全な場所を意識しながら設定変更して使うように するべきだ。
3.7節の「セッションを利用するための設定」には次の記述がある。(p.188)
セッションを利用するには、php.ini を以下のように設定してください。
(1) session.use_trans_sid = on
(2) session.save_path = 任意のディレクトリ
session.use_trans_sid を on にしてはいけない。この本 はこれを on にする理由について次のように言っているが、
デタラメである。(1)をonにすると、PHPのセッション管理関数を利用して、セッションIDの引渡 しを透過(自動)的に行えるようになります。このパラメータがoff になっている場合、セッションIDは自動的にサーバーに送信されないため、プ ログラム中で明示的に受け渡しのロジックを記述しなければなりません。
ざーーーと読み進めて、6章「テンプレートシステムを使った本格アプリケー ション 〜スケジュール管理〜」を読んでみる。ログイン機能を作ってみせる ようだ。
6.4節「ログインしてみよう」の「ログインユーザーチェックとセッション開 始」のコードはこうだ。(p.348)
function login_check($p_user, $p_pass) { $this->indi_check($p_user, "ユーザーID"); $this->indi_check($p_pass, "パスワード"); $sql = "SELECT user_id,user_name FROM user_table " ." WHERE user_id = '".$p_user."' " ." AND PASS_WORD = '".$p_pass."'"; $row_result = $this->db_object->getRow($sql,DB_FETCHMODE_ASSOC); if ($row_result["user_id"] == $p_user) { session_start(); (略) } function sub_init() { (略) $this->login_check($_POST["in_user_id"],$_POST["in_pass_word"]);
来たこれ。「indi_check」はなんだ? いわゆるひとつの「さにたいじーんぐ」か?
p.340 に書いてあった。
function indi_check($p_string, $p_name) { if (strlen($p_string) == 0) { $this->disp_err_message($p_name." は必ず入力してください"); } }
脱力。SQLインジェクション脆弱性だ。
ここまでまるまるズバリ典型的な脆弱パターンが、2004年10月発行という最近 出版の本に出ていることに驚く。インプレスでもこの程度なのか。
で、最後までパラパラと見たが、どこかに脆弱性の説明はあったのだろうかと、 索引から次のキーワードを探してみた。
ない。どれもない。
今後のあるべき姿として次などが考えられる。
というお知らせが来たが、こんな記述があった。
[2] Perl のフォーマット文字列処理の脆弱性
(略)
この問題は、Perl で書かれたプログラムを修正し、外部から入力さ れたフォーマット文字列をそのまま処理しないようにすることで解 決します。
そうじゃなくて、「外部から入力された文字列をフォーマット文字列として 使わないようにする」が正しい*1。
ここでもサニタイズ症候群か。
どんな脆弱性でも全部、「ニュウリョクヲ ソノママツカワナイ(ロボットの声で)」 と言っておけばそれっぽくまともなことを言っているかのように聞こえてしま う*2という……。そしてそれが癖になる。じつに恐ろしい。
「サニタイズすることで解決します」を「そのま ま処理しないようにすることで解決します」に置き換えたってバレ バレだ。
Advanced Web Statistics (AWStats) には、入力を適切にサニタイズしないな どの複数の脆弱性があります。
bsmptd には入力されたアドレスを適切にサニタイズしない脆弱性があります。
ここまでテンプレ化していると、サルでも書ける。というか、書いてあっても 何の情報もない。(ただしこれらは翻訳のようだ*3。 CIACとDebianの元の文書からしてサニタイズ症候群になっている。)
*1 さらに言えば、フォーマット文字列 引数(printfなどの第一引数)には常に定数文字列しか与えないようにする のが正しい。
*2 これがまたPerlが対象だといかにもそれっぽく聞こえてしまうのが 不幸だ。
*3 ちなみに、2006-01-12 のもの は翻訳ではないようだ。cert.org の元の文書には、「Programs written in Perl that contain format string vulnerabilities should be changed to not include user data in format strings.」と、正しい対策方法が書かれている。
高木さんの日記
・プログラミング解説書籍の脆弱性をどうするか
・ぜひ買いたいこの一冊(脆弱性コードレビュー練習用その1)
・しばらく日記をちゃんと書けそうにない
後藤さ
高木浩光氏の日記の記事『ぜひ買いたいこの一冊(脆弱性コードレビュー練習用その1)...
http://takagi-hiromitsu.jp/diary/20060114.html そんな高木さんにはこれをプレゼントしてあげたい. http://wiki.poyo.jp/?Reviewes%2FBook%2FIT%2FPHP#pca5de37 2005年中旬ですよ(笑
I didn't think alike on most p'ints, as on any creatur' itself cry out afore you?