| SQLインジェクション対策はおすみですか? 開発開始時点からのコンサルティングから、公開済みWebサイトの脆弱性検査、 脆弱性発見後の適切な対策まで |
2008-06-02 SQLインジェクション対策
●SQLエスケープにおける「\」の取り扱い
昨日のエントリ(徳丸浩の日記 - そろそろSQLエスケープに関して一言いっとくか - SQLのエスケープ再考)は思いがけず多くの方に読んでいただいた。ありがとうございます。その中で高木浩光氏からブクマコメントを頂戴した。
\がescape用文字のDBで\のescapeが必須になる理由が明確に書かれてない。\'が与えられたとき'だけescapeすると…。自作escapeは危うい。「安全な…作り方」3版で追加の「3.失敗例」ではDBで用意されたescape機能しか推奨していない
このうち、まず「\」のエスケープが必須となる(MySQLやPostgreSQLで)理由を説明しよう。
「\」をエスケープしないと処理がおかしくなる
MySQLにおいて、文字列「\n」は改行を意味する。その他、\に続く文字によって、様々な制御文字などを表現できるようになっている。
このため、ユーザがたまたま入力欄などから「\n」と入力した際に、エスケープしないままだと、ユーザの意図に反して「\n」が改行に化けることになる。また、エスケープシーケンスとして定義されていない場合、たとえば「\x」は単に「x」を表すと規定されているので、「tokumaru.org大安売り¥100-」が「tokumaru.org大安売り100-」となり、「¥」が欠落してしまう。これはユーザの意図ではない。
このため、「\」を「\\」エスケープすることにより、上記のような文字化けを防ぐ必要がある。これが、そもそも「\」のエスケープが必須となる理由で、セキュリティ上の要求がなくても、必要な処理である。
「\」のエスケープもれによるSQLインジェクション
上記に加えて、「\」のエスケープが必要な状況でそれがもれている場合、SQLインジェクション脆弱性の原因となる。高木氏が指摘しておられるように、「\'」という入力に対して「'」のみエスケープすると、「\''」という文字列になる。前半の「\'」で「'」を表すので、末尾の「'」がエスケープされないで残ってしまう。つまり、文字列リテラルを終端できる。前回指摘したように、これによりSQL断片を埋め込むことが可能となる。この例だと分かりにくいので、もう少し現実的な攻撃パターンで説明しよう。
SELECT * FROM XXX WHERE NN='$id' $id として \'or 1=1# が入力されると \'or 1=1# ↓ エスケープ \''or 1=1# 元のSQLに適用すると、 SELECT * FROM XXX WHERE NN='\'' or 1=1#' すなわち、SQLの構文が改変された
上記でデータベースとしてはMySQLを想定している。「#」はMySQLでコメントを表すので、行末の「#'」は無視される。
Shift_JISでの問題
ここまでならまだよい。データベースの種類によっては「\」のエスケープを忘れないようにしようで済む。ところが、文字「\」を表す文字コード0x5cがShift_JISの2バイト目にも現れうることから話がややこしくなった(一方、「'」を表す0x27の方はShift_JISの二バイト目に現れない)。0x5cを二バイト目に含む文字は多数あるが、例として以下を紹介する。
ソ(835c) 能(945c) 表(955c) 予(975c)
上記のように出現頻度の高い文字が含まれている。言語処理系やデータベースエンジン、APIなどに日本語処理の不完全な部分があると、SQLインジェクションの可能性が出てくる。
データベースエンジンの日本語処理が不完全な場合
この場合は、「表'」のような組み合わせによりSQLインジェクションができる可能性がある。
↓フロント側でのエスケープ処理
表 ' 0x95 0x5c 0x27
↓データベース側の解釈
表 ' ' 0x95 0x5c 0x27 0x27
0x95 0x5c 0x27 0x27 0x95 \' で'一文字 ' がエスケープされずに余る
このように、末尾の「'」がエスケープされない状態となり、SQLインジェクション脆弱性が生まれる。
フロント側の日本語処理が不完全な場合
フロント側(言語処理系)の日本語処理が不完全な場合も「表'」の処理において「'」のエスケープ抜けが発生する
↓フロント側でのエスケープ処理(0x5cと0x27をそれぞれエスケープ)
表 ' 0x95 0x5c 0x27
↓データベース側の解釈
0x95 0x5c 0x5c 0x27 0x27
0x95 0x5c 0x5c 0x27 0x27 「表」一文字 \'で一文字 ' がエスケープされずに余る
上記はShift_JIS固有の現象であるので、できるだけShift_JIS以外の文字エンコード、例えばUTF-8を使うとよい。しかし、ケータイブラウザのようにShift_JISのみ受け付けるものや、エンタープライズ系の応用では文字化けを避ける目的でShift_JISを要求される場合もある(入出力時に文字コード変換して処理はUnicodeに統一する手もあるが、わずらわしい場合もあるだろう)。
PostgreSQLの対応
PostgreSQLでは上記の問題に対応するために、バージョン8.1.4(2006年5月24日リリース)では、以下のような変更が行われた。
- 常にサーバ側で無効なコードのマルチバイト文字を拒否するように修正された
- 文字列リテラル中の安全でない「\'」を拒否する機能が追加された
- 以下略
上記については、ITproへの石井達夫氏による寄稿(【PostgreSQLウォッチ】第27回 SQLインジェクション脆弱性を修正,日本語ユーザーに大きな影響)が詳しい。簡単に要約すると、「\'」形式のエスケープを禁止・エラーにし、「''」方式(ISO標準)に限定できるようにした。これにより、Shift_JISの二バイト目の0x5cにまつわる「'」のエスケープ抜けを防止するというものである。但し、後方互換性の確保のため、backslash_quoteという設定パラメタが用意され、これが on の場合には、従来どおり「\'」形式のエスケープを許容する。
pg_escape_stringの挙動調査
冒頭に紹介した高木浩光氏のブクマコメントの後半は、自作のエスケープではなくDBで用意されたエスケープ機能を利用するようにという指摘であった。まことにその通りで、私のブログを読むと、自作のエスケープを推奨しているようにも読めるが、それは良くない。
それでは、PHPで用意されているpg_escape_stringは期待通り動作するのだろうか。簡単なスクリプトで検証してみた。
検証用スクリプト(PHP)
$cn = pg_connect("host=localhost user=xxxx password=xxx";
echo pg_escape_string($cn, "表\\'");
実行結果1 (standard_conforming_strings = on の場合)
表\''
実行結果2 (standard_conforming_strings = off の場合)
表\\''
PHP言語側のエスケープの都合で紛らわしいが、入力文字列は「表\'」である。前回紹介したstandard_conforming_stringsの設定を正しく反映して、onの場合は「表\''」(「\」のエスケープをしない)、offの場合には「表\\''」(「\」、「'」ともエスケープする)結果となっている。いずれの場合にも「'」は「''」とエスケープされるので、backslash_quoteの設定には依存しない。素晴らしい。
DBD::PgPPの場合
こんどはPerlでの例。PerlからPostgreSQLを利用する場合には、DBIとDBD::Pgの組み合わせが利用される・・・と思うのだが、筆者の環境では中々DBD::Pgがインストールできなかったので、代わりにDBD::PgPPを使って検証してみた。PgPPはピュアPerlで記述されたPostgreSQL用インターフェースである。DBD::PgPP中のquote()のソースを見ると、文字の変換部は以下のようになっていた(バージョン0.05)。
$s =~ s/(?=[\\\'])/\\/g; return "'$s'";
正規表現の「?=」はゼロ文字の先読み表明というやつで、後ろに「\」か「'」が続くゼロ文字にマッチする。すなわち、「\」と「'」はそれぞれ「\\」と「\'」にエスケープされる。これはいただけない。standard_conforming_stringsもbackslash_quoteも無視されている。
これは恐らくDBD::PgPPの完成度があまり高くないということなのだろう。従って、自作のエスケープをせずにDBで用意されたエスケープ機構を使えというガイドラインは一般論として正しいと思うが、上記のような例もあるので、初めて使う前に簡単なテストをしておけば安心できる。
まとめ
- 「\」のエスケープを要求するデータベースは日本語処理に特に注意
- 例えば、Shift_JISを避ける
- 自作のエスケープを避け、DBにて用意されたものを使う
- その場合でも過信は禁物で、できるならチェックしてから使うとよい
- http://takagi-hiromitsu.jp/diary/ ×244
- http://www.tokumaru.org/ ×218
- http://takagi-hiromitsu.jp/diary/20080620.html ×150
- http://www.hash-c.co.jp/ ×91
- http://b.hatena.ne.jp/HiromitsuTakagi/ ×84
- http://okyuu.com/ja/tips/986 ×75
- http://www.mixclips.org/ ×63
- http://yuki-lab.jp/diary/diar0806.html ×60
- http://www.tokumaru.org/JavaScript/ ×53
- http://d.hatena.ne.jp/ockeghem/ ×51
- http://www.hash-c.co.jp/index.html ×38
- http://okyuu.com/ja/tips/1546 ×37
- http://tokumaru.org/d/20080601.html ×33
- http://search.live.com/results.aspx?q=fizzbuzz&for... ×30
- http://yamagata.int21h.jp/d/ ×27
- http://b.hatena.ne.jp/entry/http://www.tokumaru.or... ×27
- http://codezine.jp/bookmark/hatena.aspx?dt=2008060... ×24
- http://b.hatena.ne.jp/hotentry?cname=elec ×19
- http://b.hatena.ne.jp/HiromitsuTakagi/20080602 ×18
- http://b.hatena.ne.jp/hotentry? ×17
- http://b.hatena.ne.jp/hotentry?mode=daily&date=200... ×17
- http://b.hatena.ne.jp/HiromitsuTakagi/20080603 ×15
- http://tokumaru.org/ ×14
- http://d.hatena.ne.jp/ockeghem/20080622/p1 ×13
- http://b.hatena.ne.jp/hotentry?cname=web ×12
- http://ja.reddit.com/r/ja ×12
- http://news.atode.cc/?d=20080605 ×12
- http://press.eek.jp/result/gif/gif 検査 ×11
- http://b.hatena.ne.jp/t/sqlinjection ×11
- http://d.hatena.ne.jp/ockeghem/20070528 ×11
- http://www.tokumaru.org/d/20080601.html ×9
- http://press.eek.jp/result/He/He he アップローダー ×9
- http://ja.reddit.com/r/ja/ ×9
- http://yamagata.int21h.jp/d/?date=20080603 ×9
- http://b.hatena.ne.jp/entry/8817669 ×9
- http://b.hatena.ne.jp/entry/http://www.tokumaru.or... ×9
- http://b.hatena.ne.jp/t/escape ×8
- http://press.eek.jp/result/gif/gif 画像 ×8
- http://www.tokumaru.org/techterm/ ×8
- http://press.eek.jp/result/log/log c言語 ×8
- http://d.hatena.ne.jp/ockeghem/20071210/p1 ×7
- http://www.tokumaru.org/was/ ×7
- http://b.hatena.ne.jp/t/SQLインジェクション ×7
- http://d.hatena.ne.jp/ockeghem/about ×7
- http://yamagata.int21h.jp/d/?date=20080601 ×7
- http://b.hatena.ne.jp/entrylist?url=http://&sort=h... ×7
- http://d.hatena.ne.jp/Luffy/ ×7
- http://b.hatena.ne.jp/HiromitsuTakagi/SQLインジェクション/... ×6
- http://secure.ddo.jp/~kaku/tdiary/200805.html ×6
- http://www.hash-c.co.jp/d/ ×5
- http://d.hatena.ne.jp/ockeghem/20080622/p2 ×5
- http://img.simpleapi.net/ ×5
- http://b.hatena.ne.jp/hotentry?mode=daily&date=200... ×5
- http://reddit.com/r/ja ×5
- http://okyuu.com/en/tips/986 ×5
- http://takagi-hiromitsu.jp/diary/200806.html ×5
- http://b.hatena.ne.jp/entrylist?sort=hot&of=50&thr... ×4
- http://postgresql.g.hatena.ne.jp/iakio/20080603/12... ×4
- http://codezine.jp/bookmark/hatena.aspx?dt=2008060... ×4
- http://b.hatena.ne.jp/entrylist?sort=hot&of=100&th... ×4
- http://del.icio.us/popular/sql ×4
- http://nogue.cocolog-nifty.com/diary/2007/05/refiz... ×4
- http://d.hatena.ne.jp/ikepyon/ ×4
- http://press.eek.jp/result/アップローダー/age アップローダー ×4
- http://a.hatena.ne.jp/yamagata21/ ×4
- http://clip.nifty.com/entry?url=http://www.tokumar... ×4
- http://d.hatena.ne.jp/ikepyon/20080602 ×4
- http://b.hatena.ne.jp/tyamamoto/sql/?mode=detail ×4
- http://clip.nifty.com/entry/531e0f11b3b826fcfe8655... ×3
- http://mgw.hatena.ne.jp/?url=http://www.tokumaru.o... ×3
- http://www.kernel-net.ne.jp/tech/index.php?脆弱性関連 ×3
- http://www.math.sansu.org/u/diary/?date=20070604 ×3
- http://b.hatena.ne.jp/entry/5892458 ×3
- http://www.rider-n.sakura.ne.jp/blog/ ×3
- http://fastladder.com/subscribe/http://www.tokumar... ×3
- http://nogue.cocolog-nifty.com/ ×3
- http://clip.livedoor.com/ ×3
- http://b.hatena.ne.jp/HiromitsuTakagi/セキュリティ/ ×3
- http://d.hatena.ne.jp/kazuhooku/20080623/121418874... ×3
- http://sideblue.net/ ×3
- http://www.tokumaru.org/d/20080502.html ×3
- http://del.icio.us/popular/security ×3
- http://209.85.175.104/search?q=cache:H1qBXyfgLI4J:... ×3
- http://del.icio.us/rss/popular/security ×3
- http://b.hatena.ne.jp/t/escape?sort=eid ×3
- http://d.hatena.ne.jp/ockeghem/searchdiary?word=SQ... ×3
- http://s.luna.tv/search.aspx?client=lunascape&s=0&... ×3
- http://d.hatena.ne.jp/ikepyon/200806 ×3
- http://www.tokumaru.org/d/20080722.html ×3
- http://search.live.com/results.aspx?q=rebinding&fo... ×3
- http://d.hatena.ne.jp/teracc/20070715 ×3
- http://d.hatena.ne.jp/f-star/?of=1 ×3
- http://b.hatena.ne.jp/t/postgresql ×3
- http://yamagata.int21h.jp/d/?category=ALL;year=200... ×2
- http://yamagata.int21h.jp/d/?category=ALL;year=200... ×2
- http://www.math.sansu.org/u/diary/?date=200706 ×2
- http://r.hatena.ne.jp/toguo/hatebu/?mode=feedtable... ×2
- http://search.live.com/results.aspx?q=SQL インジェクション... ×2
- http://www.tokumaru.org/index.htm ×2
- http://s.luna.tv/search.aspx?q=CSRF セキュリティ&st=30&d... ×2
- SQL エスケープ ×31 / javascript break ×13 / 徳丸浩 ×13 / sql エスケープ ×11 / SQLインジェクション エスケープ ×10 / SQLインジェクション 対策 ×8 / sql escape ×7 / SQL 必須 エスケープ ×6 / 0x95 ×6 / 画像 クロスサイト ×5 / FizzBuzz問題 perl ×5 / mod_imagefight ×5 / エスケープ SQLインジェクション ×4 / SQLインジェクション sqlserver ×4 / escape sql ×4 / DB エスケープ ; ×4 / sql エスケープ 必要 文字 ×4 / jpegファイル xss ×4 / エスケープ文字 ×4 / sql ' エスケープ ×4 / sql server エスケープ文字 ×4 / バインド機構 postgre ×4 / PHP 入力値エスケープ ×3 / IEEE754 正規化 ×3 / IE HTML 画像 埋め込み ×3 / データベース エスケープ処理 ×3 / SQLインジェクション 対策 エスケープ ×3 / Base64 javascript IE 画像 ×3 / IEEE 754 ×3 / sql 数値 クオート ×3 / php POSTデータ検査 ×3 / SQLインジェクション 文字コード ×3 / クロスサイトスクリプティング サンプル ×3 / http://www.tokumaru.org/d/20080602.html ×3 / 金床 セキュリティ ×3 / sql 文字列 単一引用符 ×3 / SQL エスケープ sqlserver ×3 / mysql エスケープ文字列 ×3 / SQL サニタイズ SQLサーバー エスケープ ×3 / PHP PostgreSql SQLインジェクション ×3 / oracle sql エスケープ ×3 / ソ 文字化け sql ×2 / SQLインジェクション対策 ×2 / エスケープ処理とは perl ×2 / sql 文字 エスケープ ×2 / postgresql エスケープ シングル ×2 / sql 数字項目 ×2 / xss 徳丸 ×2 / postgres エスケープ E\'\' ×2 / ESCAPE SQL ×2 / sql escape dbi ×2 / クロスサイト スクリプティング 対策 コード sanitize /e /g ×2 / UTF-8 ShiftJIS 0x5C Perl 文字化け 対策 ×2 / mysql コメント エスケープ ×2 / HASHコンサルティング株式会社 ×2 / 画像 XSS ×2 / SQLインジェクション 対策 エスケープ文字 ×2 / SQLインジェクション 置き換え Perl ×2 / データベース エスケープ文字 ×2 / MySQL 文字化け エスケープ ×2 / oracle エスケープ 記号 ×2 / asp.net iis jpeg 表示できない ×2 / sql server インジェクション ×2 / sqlインジェクション対策 徳丸 ×2 / postgresql 改行文字 エスケープ ×2 / sql ESCAPE ×2 / php 複文 ×2 / DNS Rebinding ×2 / PHP SQLインジェクション例 ×2 / html エスケープ ×2 / SQL 記号文字 ×2 / sqlインジェクション エスケープ ×2 / エスケープ 末尾 sql インジェクション ×2 / PHP SQLインジェクション例 ソ ×2 / SQLインジェクション 対策 ' " \ ×2 / sqlserver 引用符 エスケープ ×2 / mysql エスケープ ×2 / SQL "Escape $" ×2 / SQL DATABASE 内容改竄 ×2 / sql インジェクション 対策 エスケープ ×2 / sql エスケープ escape ×2 / mysql sqlインジェクション 文字列 "\"で ×2 / postgres エスケープシーケンス ×2 / MySQL 文字 エスケープ ×2 / standard_conforming_strings ×2 / SQLエスケープ再考 ×2 / perl DBI SQL インジェクション ×2 / エスケープ sql ×2 / postgresql 正規表現 エスケープ ×2 / switch break ×2 / インジェクション エスケープ ×2 / 徳丸 SQL ×2 / 0x5c SQLインジェクション ×2 / sql エスケープ 必要 ×2 / sqlインジェクション 対策 エスケープ ×2 / javascript switch ×2 / sqlインジェクション対策 ×2 / Postgres エスケープ文字 変換 ×2 / mssql エスケープ ×2 / UTF エスケープ PostgreSQL Perl ×2
| SQLインジェクション対策はおすみですか? 開発開始時点からのコンサルティングから、公開済みWebサイトの脆弱性検査、 脆弱性発見後の適切な対策まで |