SQLインジェクションのサンプルが動かない

 前回に引き続き、はじめてのPHPプログラミング 基本編5.3対応のゆるいところ第四段は、SQLインジェクションのサンプルについてだ。
 本書にはプログラミングの入門書としては珍しくSQLインジェクションの説明がある。それはよいことなのだが、P242の以下の記述には少し問題がある。


また、「'; UPDATE addressbook SET address = '北海道」という文字列が代入されていたら…。お分かりですね。次のようなSQLになり、すべての住所が書き換えられてしまいます。

SELECT name, address FROM addressbook WHERE id = ''; UPDATE addressbook SET address = '北海道'
「はじめてのPHPプログラミング基本編5.3対応」P242より引用

 SQLのSELECT文とUPDATE文がセミコロンで区切られている上記のような形式を複文(multiple statement)というが、SQLインジェクションの文脈でこれが実際に動作するかどうかは、DBと言語(ライブラリ)の組み合わせで決まる。詳しくは複文が利用できるデータベースの調査: SQL Serverが狙われるには理由がある - 徳丸浩の日記(2008-05-02)を参照されたい。
 SQLiteの場合はどうだろうか。試してみたところ、SELECTのような参照系で用いる関数sqlite_query()を使う場合、上記のSQLはエラーにならずSELECTの結果は受け取れたが(検索結果が存在する場合)、UPDATEは実行されないようだ。このため実際には、「すべての住所が書き換えられてしまいます」という状況にはならない。一方、クエリ結果を返さない関数sqlite_execute()を使った場合は、「UPDATE〜;UPDATE〜」という形式のSQLで、両方のUPDATEの実行が確認できた。すなわち、先に調べた結果とあわせると以下のようになる。

SQL Server MySQL PostgreSQL Oracle SQLite
PHP × ×
Java × ×
Perl × ×

凡例:
○:複文に対応
△:更新系のSQLであれば複文に対応
×:複文に非対応

 本書のこの部分は、SQLインジェクションの脅威を説明しているところだから、上記は致命的なミスではないと思うが、例として示すからには動くものを示すべきだろう。私もモノ書きの端くれとして、自戒の念を込めてそう思う。
 このテーマを取り上げた理由は、私の個人的体験と重なるからだ。2000年頃、はじめてSQLインジェクションの紹介に接したとき、ちょうど上記のようなSELECTとUPDATEの組み合わせが説明されていた。私は手近な環境(おそらくOracle)で動かしてみたのだが、動かなかった。最初、自分のやり方が悪いと思ったのだがどうしてもうまくいかず、最終的に「セキュリティ専門家の言うことはあてにならない」という感想を持った。
 その後歳月が流れて、自分自身が「セキュリティの専門家」になったわけだが、初心は忘れないようにしようというわけで、コードのサンプルを示すときには本当に動くか確かめてから載せるようにしている(たまに怠って冷や汗をかくわけだが)。言葉にすると、わざわざ威張るほどのことでもない当たり前のことだが、その当たり前をしていない「専門家」が多いのが現状だ。
 おそらく、下岡氏らは、私が見たのと同じようなサンプルを調べて、「専門家が書いているから大丈夫だろう」と思ってそのまま利用されたのではないか。だとすれば、これは下岡氏らの責任もさることながら、いい加減なSQLインジェクションのサンプルを紹介し続けてきた「セキュリティの専門家」の罪ともいえると私は考えている。