| SQLインジェクション対策はおすみですか? 開発開始時点からのコンサルティングから、公開済みWebサイトの脆弱性検査、 脆弱性発見後の適切な対策まで |
2008-10-29
●書籍「はじめてのPHPプログラミング基本編5.3対応」にSQLインジェクション脆弱性
id:hasegawayosuke氏にそそのかされるような格好で、「はじめてのPHPプログラミング基本編5.3対応」という書籍を購入した。
本書は、ウノウ株式会社の下岡秀幸氏、中村悟氏の共著なので、現役バリバリのPHP開発者が執筆しているということ、下記のようにセキュリティのことも少しは記述されているらしいという期待から購入したものだ。
目次から抜粋引用 07-07 Webアプリケーションのセキュリティ [セキュリティ] 08-04 データベースのセキュリティ [SQLインジェクション] 09-13 セキュリティ対策 [セキュリティ]
本書をざっと眺めた印象は、「ゆるいなぁ」というものであるが、その「ゆるさ」のゆえんはおいおい報告するとして、その経過で致命的な脆弱性を発見したので報告する。
問題の報告
それは、本書P280に登場する「SQLインジェクション対策用の関数(dbescape)」だ。この関数を本書から引用する。
// SQLインジェクション対策用の関数
function dbescape($sql, array $params)
{
foreach ($params as $param) {
// パラメータの型によって埋め込み型を変える
switch (gettype($param)) {
case "integer":
case "double":
$replacement = $param;
break;
case "string":
// 文字列の場合はエスケープ処理をおこなう
$replacement = sprintf("'%s'", sqlite_escape_string($param));
break;
default:
die("パラメータの型が正しくありません");
}
// SQLを置換し、パラメータを埋め込む
$sql = substr_replace($sql, $replacement, strpos($sql, "?"), 1);
}
// すべてパラメータを埋め込んだSQLを返す
return $sql;
}
この関数は、「穴埋め形式のSQL文字列と、埋め込むパラメータの配列を受け取り、必要なエスケープ処理を施したSQL文字列を返します」とのことで、以下のように用いる。
$sql = dbescape("SELECT COUNT(id) FROM friend WHERE from_name = ? AND to_name = ?",
array($from_name, $to_name));
これに対して、$from_name = "Johnson"、$to_name = "M'Intosh" として上記を実行すると、以下のような文字列が返る
SELECT COUNT(id) FROM friend WHERE from_name = 'Johnson' AND to_name = 'M''Intosh'
すなわち、バインド機構を自前で実現したようなインターフェースである。
この実装を見た瞬間、違和感を感じた。これは書式文字列の処理に属するものであるので、通常は書式文字列($sql)を左から調べて、書式記号(?)が出てくるたびに、対応するパラメータの処理を行うのが定石的な実装だと思う。そうでないと(上記の場合は出てこないが)書式などのエスケープを上手く処理できない。しかるに、引用した関数では、パラメータの方を調べながら、対応する書式記号(?)を探している。しかも、未処理の部分と処理済の部分がごちゃまぜになっているので、まずいことが起こりそうである。
そう、この関数にはバグがある。パラメータとして"?"を含む文字列を与えた場合、元の穴埋め式SQLに存在した"?"と、新たに埋め込まれた"?"がごっちゃになる。試してみよう。先の例に、第一パラメータとして"?"、第二パラメータとして"AAA"を与えた場合の処理の流れは以下のようになる
0:SELECT COUNT(id) FROM friend WHERE from_name = ? AND to_name = ?
↑ '?' に置き換え
1:SELECT COUNT(id) FROM friend WHERE from_name = '?' AND to_name = ?
↑ 'AAA' に置き換え
2:SELECT COUNT(id) FROM friend WHERE from_name = ''AAA'' AND to_name = ?
ご覧のように、第一パラメータの変換結果である '?' から、さらに?部分が'AAA'に置き換わることから、意図した結果を得られない。しかも、右側の"?"があまってしまい、SQLの文法違反となる。

それだけならまだよいのだが、AAAの部分に着目いただきたい。この部分は外部から与えた文字列なので、シングルクォートで囲まれてなければならないのだが、上記の過程で、文字列リテラルからはみ出した、すなわちSQL文の式の一部として解釈される状態となった。この時点でSQLインジェクション脆弱性といえる(ライオン(=外部からの文字列)が檻(=文字列リテラル)から抜け出した状態)。
従って、AAAの代わりにSQL文をセットしてやれば、任意のSQLが実行できることになる。やってみよう。今度は第二パラメータとして"or 1=1--"をセットしてやる。変換後のSQLはこうなる。
SELECT COUNT(id) FROM friend WHERE from_name = ''or 1=1--'' AND to_name = ?
本書で想定しているRDB(SQLite)では、--は標準SQL同様コメントとなるので、--から先は無視される。すなわち、SQLの意味が書き換えられた。SQLiteではUNIONをサポートしているし、更新系SQLでは複文をサポートするようなので、様々な悪用が可能となる。
教訓
あらゆるバグは脆弱性になり得る
どうすべきだったか
汎用的なsqlエスケープ関数を用意して、対策をこの関数にカプセル化しようという心意気はよかったのだが、あいにくこの関数にバグがあって、意図がかえって仇となる結果となった。では、どうすればよかったか。
思うに、バインド機構に似た機能を自作しようというのが間違いで、そんなに簡単にできるものではない。PHPのsqlite_xxxx系の関数にはバインド機構が用意されていないようだが、PDOを利用することで、SQLiteでもバインド機構が利用できる。
あるいは、SQLiteの使用をあきらめ、MySQLを使ってもよかった。本書のカバーには「MySQL(データベース)」とある(これはCD-ROMにMySQLが添付されているということらしい)。WindowsでもMySQLは動作するし、実務でも利用機会はMySQLの方がずっと多いだろう。MySQLであれば、mysql_xxxx系の関数でバインド機構が利用できる。さらに大切なこととして、「SQLインジェクション対策は原則としてバインド機構を用いるべし」という原則を教えることもできるのだから。
via. 徳丸浩の日記 - 書籍「はじめてのPHPプログラミング基本編5.3対応」にSQLインジェクション脆弱性 データベースのセキュリティについて徳丸浩氏に指摘頂きました。ありがとうございます。 問題の報告 それは、本書P280に登場する「SQLインジェクション対策用の関数(dbes
先日の日記徳丸浩の日記 - 書籍「はじめてのPHPプログラミング基本編5.3対応」にSQLインジェクション脆弱性にて、はじめてのPHPプログラミング 基本編―5.3対応を取り上げた際に、『その「ゆるさ」のゆえんはおいおい報告する』と予告していた。書くネタは決まっていたの
- http://php.designlinkdatabase.net/data/frame_21350... ×5 : 4, 1
- http://yokosan4.sakura.ne.jp/hatena_toplink.php ×1
- http://clip.nifty.com/entry/531e0f11b3b826fcfe8655... ×1
- http://www.tokumaru.org/ ×288
- http://www.st.ryukoku.ac.jp/~kjm/security/memo/ ×226
- http://secure.ddo.jp/~kaku/tdiary/ ×185
- http://www.doyouphp.jp/book/book_hajimete.shtml ×149
- http://www.st.ryukoku.ac.jp/~kjm/security/memo/200... ×147
- http://d.hatena.ne.jp/ockeghem/20081101/p1 ×121
- http://www.hash-c.co.jp/ ×108
- http://www.tokumaru.org/JavaScript/ ×106
- http://d.hatena.ne.jp/shimooka/20081029/1225247796... ×92
- http://b.hatena.ne.jp/entry/http://www.tokumaru.or... ×80
- http://ideaup.seesaa.net/article/108141154.html ×74
- http://www.ideaxidea.com/archives/2008/10/php_1.ht... ×66
- http://b.hatena.ne.jp/HiromitsuTakagi/ ×64
- http://bakera.jp/ebi ×57
- http://d.hatena.ne.jp/shimooka/ ×49
- http://d.hatena.ne.jp/ockeghem/20080622/p1 ×47
- http://labs.unoh.net/2008/10/php_53.html ×36
- http://bakera.jp/ebi/topic/3330 ×35
- http://d.hatena.ne.jp/ockeghem/ ×27
- http://d.hatena.ne.jp/ockeghem/?of=5 ×23
- http://d.hatena.ne.jp/ockeghem/20081109/p1 ×23
- http://b.hatena.ne.jp/hotentry? ×20
- http://www.tokumaru.org/was/ ×17
- http://d.hatena.ne.jp/ockeghem/20081112/p1 ×17
- http://d.hatena.ne.jp/teracc/20070715 ×17
- http://blog.webcreativepark.net/2008/10/24-201629.... ×17
- http://okyuu.com/ja/tips/986 ×16
- http://okyuu.com/ja/tips/1546 ×16
- http://yamagata.int21h.jp/d/ ×16
- http://www.tokumaru.org ×16
- http://memo.hirosiki.jp/article/108099626.html ×16
- http://d.hatena.ne.jp/ockeghem/20081101 ×15
- http://isma44.egloos.com/4642630 ×13
- http://bakera.jp/ebi/topic/3295 ×13
- http://www.tokumaru.org/index.htm ×13
- http://b.hatena.ne.jp/hotentry?cname=web ×12
- http://b.hatena.ne.jp/HiromitsuTakagi/20081030 ×12
- http://blog.ohgaki.net/php-session ×11
- http://blog.ohgaki.net/-13 ×11
- http://d.hatena.ne.jp/ockeghem/20071210/p1 ×11
- http://labo.shimi-zoo.com/?q=node/32 ×11
- http://d.hatena.ne.jp/ockeghem/?of=10 ×10
- http://bakera.jp/ebi/topic/3217 ×10
- http://209.85.175.104/search?q=cache:JbFWF9fAeQEJ:... ×10
- http://koteitan.seesaa.net/article/95301330.html ×9
- http://www.hash-c.co.jp/d/ ×8
- http://takagi-hiromitsu.jp/diary/20080620.html ×8
- http://takagi-hiromitsu.jp/diary/200806.html ×8
- http://d.hatena.ne.jp/ockeghem/20071021/1192986523... ×8
- http://tokumaru.org/d/20080601.html ×7
- http://www.tokumaru.org/JavaScript/index.htm ×7
- http://b.hatena.ne.jp/t/php ×7
- http://d.hatena.ne.jp/hsada/20080603/1212421919 ×7
- http://www.tokumaru.org/techterm/ ×7
- http://codezine.jp/bookmark/ ×7
- http://hash-c.co.jp/ ×6
- http://img.simpleapi.net/ ×6
- http://d.hatena.ne.jp/ockeghem/about ×6
- http://takagi-hiromitsu.jp/diary/20080727.html ×6
- http://d.hatena.ne.jp/ockeghem/20080708 ×6
- http://d.hatena.ne.jp/hasegawayosuke/20071226/p1 ×6
- http://okyuu.com/ja/tips/2803 ×5
- http://okyuu.com/ja/tips/3484 ×5
- http://b.hatena.ne.jp/entry/http://www.tokumaru.or... ×5
- http://bakera.jp/ebi/topic/2986 ×5
- http://clip.livedoor.com/hot/ ×5
- http://b.hatena.ne.jp/entrylist?url=http://&sort=h... ×5
- http://phpspot.org/blog/archives/2008/10/20081016.... ×5
- http://www.tokumaru.org/d/20070924.html ×5
- http://del.icio.us/rss/popular/security ×5
- http://secure.ddo.jp/~kaku/tdiary/20081029.html ×5
- http://b.hatena.ne.jp/entrylist?sort=hot&of=50&thr... ×5
- http://b.hatena.ne.jp/ockeghem/SQL Server/ ×4
- http://b.hatena.ne.jp/entrylist?url=http://www.tok... ×4
- http://b.hatena.ne.jp/hasegawayosuke/ ×4
- http://reader.livedoor.com/subscribe/http://www.to... ×4
- http://secure.ddo.jp/~kaku/tdiary/200810.html ×4
- http://d.hatena.ne.jp/fmaction/20081016/1224118316... ×4
- http://buzzurl.jp/entry/徳丸浩の日記 - 書籍「PHP×携帯サイト デベロッ... ×4
- http://pfrb.blog114.fc2.com/blog-entry-6.html ×4
- http://www.kt.rim.or.jp/~kbk/zakkicho/index.html ×4
- http://news.qooqle.jp/ ×4
- http://b.hatena.ne.jp/miyagawa/ ×4
- http://takagi-hiromitsu.jp/diary/20070223.html ×4
- http://www.tokumaru.org/d/20070717.html ×4
- http://d.hatena.ne.jp/ockeghem/20071010/1192009917... ×4
- http://b.hatena.ne.jp/HiromitsuTakagi/?of=40 ×4
- http://b.hatena.ne.jp/entrylist?sort=hot&of=50&thr... ×4
- http://b.hatena.ne.jp/HiromitsuTakagi/?of=20 ×4
- http://clip.livedoor.com/ ×4
- http://b.hatena.ne.jp/entry/5892458 ×4
- http://www.hash-c.co.jp/d/20080622.html ×3
- http://search.live.com/results.aspx?q=rebinding ×3
- http://sbm.webcreativepark.net/bookmarks.php/kazum... ×3
- http://www.junk-search.com/tag/nsr250r 88.html ×3
- http://security.c-inf.com/index.php?Cross Site Scr... ×3
- http://search.live.com/spresults.aspx?q=携帯のホワイトリスト... ×3
- http://search.live.com/results.aspx?q=imagefight ×3
- http://stressfulangel.cocolog-nifty.com/stressful_... ×3
- http://www.kt.rim.or.jp/~kbk/zakkicho/ ×3
- javascript break ×50 / WAF ×35 / 徳丸浩 ×29 / キーワード不明 ×18 / SQLインジェクション 対策 ×18 / waf ×16 / PHP×携帯サイト デベロッパーズバイブル ×12 / javascript ラベル ×10 / XSS 動的 ×9 / bmp internet explorer xss ×8 / sqlserver 攻撃 ×7 / 徳丸 gif ×7 / session_set_save_handler ×7 / SQLインジェクション PHP 対策 ×6 / DNS rebinding ×6 / bmp xss internet explorer ×6 / sql escape ×6 / sql インジェクション 対策 ×5 / PHP 書籍 ×5 / 画像ファイル XSS ×5 / xss jpeg ×5 / 徳丸 画像 XSS ×5 / 携帯サイト 書籍 ×5 / mysql "記号文字" エスケープ ×4 / mysql エスケープ文字 ×4 / 暗黙の型変換 postgresql ×4 / JPG javascript埋め込み ×4 / 徳丸 日記 ×4 / 携帯サイト 開発 セキュリティ対策 ×4 / 画像 スクリプト 埋め込み ×4 / perl Pgpp 文字化け ×4 / シングルクォート sql ×4 / xss エンコード javascript ×4 / sqlインジェクション 対策 ×4 / 画像XSS ×4 / XSS 画像 マジックバイト ×4 / 徳丸 WAF ×3 / javascript switch ×3 / WAF サニタイズ ×3 / JavaScriptを埋め込んだ画像 ×3 / Content-Type無視 クロスサイト ×3 / sql エスケープ 円記号 ×3 / javascript for break ×3 / sql update 変数 ×3 / シグネチャ 定義ファイル ホワイトリスト ×3 / dns rebinding ×3 / mysql escape ×3 / XSS ×3 / javascript jpg 埋め込む ×3 / javascript xss ×3 / 画像 形式 先頭 バイト GIF ×3 / SQL Injection 改行コード エスケープシーケンス ×3 / "SQL インジェクション" PQexecParams ×3 / IEEE-754 ×3 / document.cookie alert php ×3 / ホワイトリスト SQLインジェクション ×3 / IPS HIDDENフィールド ×3 / bmp xss ×3 / pg_escape_string() 数値 ×3 / SQL エスケープシーケンスとは ×3 / 文字コード 0x27 ×3 / mod_imagefight ×3 / java oracle SQLインジェクション エスケープ処理 ×3 / XSS javascript ×3 / sqlインジェクション エスケープ ×3 / au セッション cookie ×3 / mysql 円記号 ×3 / sql エスケープ ’’ ×3 / SQL バックスラッシュ ×3 / xss テスト ×3 / 暗黙の型変換 sqlserver ×3 / DNS Rebinding ×3 / wafとは ×3 / php session_set_save_handler ×3 / SQL バインド機構 perl ×2 / 個体識別 脆弱性 ×2 / エスケープ 正規表現 SQL ×2 / 初めて php開発 ×2 / XSS 画像 ×2 / PNGイメージ 表示できない ×2 / pg_escape_string,空白 ×2 / ブラックリスト ホワイトリスト ×2 / はじめてのPHPプログラミング ×2 / sqlserver php escape ×2 / はじめてのPHPプログラミング 基本編 ×2 / SQL 単一引用符 エスケープ ×2 / javascriptのパラメータ検証ライブラリ ×2 / MSSQL バインド機構 ×2 / Ruby SQLインジェクション対策 ×2 / MySQLインジェクション 対策 ×2 / SQL オラクル ESCAPE ×2 / PHP SQL Server エスケープ ×2 / posgre エスケープ シーケンス ×2 / SQL Server SQLインジェクション対策 ×2 / ホワイトリスト ブラックリスト ×2 / SQLインジェクション対策 ×2 / sql インジェクション対策 ×2 / Sanitize sql oracle ×2 / バインド機構とは MYSQL ×2 / サニタイジング文字 DB2 ×2
| SQLインジェクション対策はおすみですか? 開発開始時点からのコンサルティングから、公開済みWebサイトの脆弱性検査、 脆弱性発見後の適切な対策まで |