| SQLインジェクション対策はおすみですか? 開発開始時点からのコンサルティングから、公開済みWebサイトの脆弱性検査、 脆弱性発見後の適切な対策まで |
2007-09-24 変数に型のない言語におけるSQLインジェクション対策に対する考察(5)
●数値項目に対するSQLインジェクション対策のまとめ
一連の議論では、以下の条件におけるSQLインジェクション対策について議論している。
- SQLインジェクション対策において、バインド機構が利用できない(したくない)
- 変数に型のない言語(Perl、PHP、Rubyなど)を使用している
- 数値型の列の場合
この場合の対策としては、以下の二種類が機能する。
- SQL文組み立ての前に、数値としての妥当性検証を行う
- 数値項目もシングルクォートで囲み(クォートし)、文字列リテラルと同様のエスケープを行う
数値項目もクォートする方法
このうち、後者の積極的な推進者として大垣靖男氏がおられる。例えば、以下のような記事
すべての変数をエスケープする対策
この方法はすべてのデータベースに利用できる対策です。文字列,整数などデータ型に関わらず変数すべてを文字列としてエスケープすることにより,SQLインジェクションを100%防ぐことが可能となります。例えば,PostgreSQLのSQL文を生成する場合,以下のようにすべてのパラメータを文字列して処理・生成します。
$sql = "UPDATE user SET name = '".pg_escape_string($_POST['name'])."', age = '".pg_escape_string($_POST['age'])."' WHERE id = '".pg_escape_string($_SESSION['USERID'])."';";
[なぜPHPアプリにセキュリティホールが多いのか?:第5回 まだまだ残っているSQLインジェクション(2ページ目)より引用]
上記の「"', age = '".pg_escape_string($_POST['age'])."' WHERE id = '"」の部分がそれである。age欄が「24」の場合、SQLの関連部分は以下のようになる。
UPDATE user SET name = 'ほげほげ', age = '24' where 【後略】
一方、age欄が「';DROP TABLE user--」の場合は、
UPDATE user SET name = 'ほげほげ', age = ''';DROP TABLE user--' where 【後略】
このようにこのSQLはageという数値項目に、数値でない文字列をセットしようとしているので、実行時にエラーとなる*1が、SQLインジェクションは回避される。
SQLにおける暗黙の型変換の是非
数値をクォートして文字列にすると、SQL実行時には、数値型の列と文字列リテラルとの間に「暗黙の型変換」が発生する。先の例では、age列が整数型だとして、set ... age = '24' ...という式の実行時に、文字列('24')から、数値(24)への暗黙の型変換が発生する。
一般に、プログラミングの分野では「暗黙の型変換」が有害であると言われる場合があるが、SQLの場合はどうだろうか。たとえば、Oracle Technology Network(OTN)には、以下のようなドキュメントがある。
暗黙的なデータ変換と明示的なデータ変換
次の理由から、暗黙的な変換または自動変換ではなく、明示的な変換を指定することをお薦めします。
- 明示的なデータ型変換ファンクションを使用すると、SQL文がわかりやすくなります。
- 暗黙的なデータ型変換(特に列値のデータ型が定数に変換される場合)は、パフォーマンスに悪影響を及ぼす可能性があります。
- 暗黙的な変換はその変換が行われるコンテキストに依存し、どんな場合でも同様に機能するとはかぎりません。たとえば、日時値からVARCHAR2型へ値を暗黙的に変換すると、NLS_DATE_FORMATパラメータに指定されている値によっては、予期しない年が戻される場合があります。
- 暗黙的な変換のアルゴリズムは、ソフトウェア・リリースやOracle製品の変更によって変更されることがあります。明示的な変換を指定しておくと、その動作は将来的にも確実になります。
[Oracle SQLの基本要素より引用]
このように、暗黙の型変換は、実装依存であるため動作が不確実になることや、性能面の不利などで推奨されていないことがわかる。
興味深いデータがある。ockeghem(徳丸浩)の日記 - 数値リテラルをシングルクォートで囲むことの是非を書いて以来、筆者のブログに「ORA-01722」の検索キーワードで訪れた人が累計74人もおられる。同じキーワードにより、Gooleなどで検索してみると、、同エラーコードに対する対処法の質問や、対処法FAQの説明などがいくつもヒットする。FAQができるくらい「暗黙の型変換」にはまる人が多いことになる。筆者のブログへの来場者も、現実に「ORA-01722」のエラーで困り果てた末にやってきて、がっかりして(なんだ、SQLインジェクションの説明か)立ち去った人が大半ではないだろうか。すなわち、現実に暗黙の型変換は、予期しない問題に遭遇する可能性が高く、書法的に推奨されない。
数値をクォートすると性能が悪化するケース
次に性能面ではどうか。筆者自身は、数値をクォートすることで性能劣化するパターンを見つけられていなかった*2が、最近奥 一穂のお仕事ブログに興味深いデータが示された。
鴨志田さんに教えていただいたのですが、MySQL のクエリは数値をクォートしない方が高速になるらしいです。たとえば以下の例では、160万件の整数から4の倍数を数えていますが、数値をクォートしないほうが約50%も高速になっています。
[Kazuho@Cybozu Labs: MySQL の高速化プチBKより引用]
筆者も手元のノートPCで追試を試みたところ、50%もの差はでなかったが、数値をクォートしない方が約20%高速になるという結果が確認できた*3。
また、SQLインジェクション対策に限らず、SQLにおける暗黙の型変換という広い文脈でとらえると、既に報告の通り、インデックスが利用されなくなるために性能が大幅に低下する場合がある。
ではどうしたらよいか
今まで見てきたように、数値をクォートしてエスケープする方法は、数値項目に対するSQLインジェクション対策としては機能するが、副作用が多い。筆者としてはSQLを組み立てる直前での数値チェックをお勧めしたい。以下のような仕様の関数を作ればよいだろう。
- 入力パラメータを数値として妥当性チェックする
- 妥当の場合は数値をそのまま返す
- 妥当でない場合は例外を発生させる
この関数は、pg_escape_stringなどと同じように使える*4ので、置き換えなどもしやすいであろう。先にあげた「暗黙の型変換」のデメリットが解消されるだけでなく、SQL実行前にエラー(例外)にできるので、アプリケーションの信頼性という点でも少し有利であろう。
なお、このエントリーはSQLインジェクション対策のための数値チェックであるが、アプリケーションの信頼性向上のための「入力値検証」は、上記とは独立に実施されることをおすすめする*5。
自作コンパイラの部屋 > Web Application Security(WAS)に関する話題の目次 - SQLインジェクション > 数値項目に対するSQLインジェクション対策のまとめ
*1 ockeghem(徳丸浩)の日記 - 数値リテラルをシングルクォートで囲むことの是非参照
*2 SQLの「暗黙の型変換」で実行速度が遅くなるのはどのような場合か参照
*3 奥氏の環境はMyISAMだが、筆者の環境はInnoDBというエンジンの違い、奥氏はキー指定をしていないが、徳丸はキー指定をしているなどの違いに依存するものと思われる
*4 数値のクォートは外す必要がある
- tDiary.Net ×1
- http://www.tokumaru.org/ ×580
- http://www.tokumaru.org/JavaScript/ ×190
- http://d.hatena.ne.jp/ockeghem/20071010/1192009917... ×54
- http://labs.cybozu.co.jp/blog/kazuho/archives/2007... ×46
- http://d.hatena.ne.jp/ockeghem/ ×39
- http://d.hatena.ne.jp/teracc/20070715 ×34
- http://d.hatena.ne.jp/ockeghem/20070528 ×26
- http://d.hatena.ne.jp/ockeghem/20071021/1192986523... ×23
- http://www.hash-c.co.jp/ ×15
- http://b.hatena.ne.jp/entry/5303987 ×14
- http://www.tokumaru.org/was/ ×11
- http://b.hatena.ne.jp/entry/http://www.tokumaru.or... ×11
- http://www.tokumaru.org/JavaScript/index.htm ×11
- http://b.hatena.ne.jp/entry/5973225 ×11
- http://tokumaru.org/ ×10
- http://d.hatena.ne.jp/ockeghem/20070502/1178042280... ×10
- http://a.hatena.ne.jp/yamagata21/ ×10
- http://b.hatena.ne.jp/t/SQLインジェクション ×10
- http://dragon.jp/column/archives/cookie.html ×9
- http://d.hatena.ne.jp/ockeghem/20070717/1184686116... ×9
- http://d.hatena.ne.jp/ockeghem/20071010/1191985572... ×9
- http://www.tokumaru.org/index.htm ×8
- http://b.hatena.ne.jp/keyword/SQLインジェクション ×8
- http://d.hatena.ne.jp/teracc/ ×8
- http://www.about-reference.com/php/manual/function... ×7
- http://d.hatena.ne.jp/teracc/20070908 ×7
- http://bakera.jp/ebi/topic/2986 ×7
- http://www.saiyasuweb.com/2/c/クッキー ×7
- http://a.hatena.ne.jp/ockeghem/ ×7
- http://d.hatena.ne.jp/ockeghem/about ×6
- http://b.hatena.ne.jp/entry/http://www.microsoft.c... ×6
- http://d.hatena.ne.jp/ockeghem/20071010 ×6
- http://a.hatena.ne.jp/harupu/ ×6
- http://tokumaru.org/d/20080601.html ×6
- http://press.eek.jp/result/アップローダー/age アップローダー ×5
- http://www.about-reference.com/php/pear_manual/pac... ×5
- http://labs.cybozu.co.jp/blog/kazuho/archives/2007... ×5
- http://d.hatena.ne.jp/m383m/20070918/1190100985 ×5
- http://www.math.sansu.org/u/diary/?date=20070604 ×5
- http://b.hatena.ne.jp/keyword/サニタイズ ×5
- http://b.hatena.ne.jp/keyword/XSS?of=25&sort=hot&t... ×5
- http://d.hatena.ne.jp/butyricacid/20070820/1187561... ×4
- http://search.live.com/results.aspx?q=imagefight&m... ×4
- http://d.hatena.ne.jp/ockeghem/searchdiary?word=セキ... ×4
- http://www.devnull.jp/tdiary/ ×4
- http://www.math.sansu.org/u/diary/ ×4
- http://b.hatena.ne.jp/t/sqlインジェクション ×4
- http://a.hatena.ne.jp/mao140/ ×4
- http://b.hatena.ne.jp/TAKESAKO/20070924 ×4
- http://b.hatena.ne.jp/HiromitsuTakagi/?of=20 ×4
- http://b.hatena.ne.jp/t/入力値チェック ×3
- http://b.hatena.ne.jp/oooooooo/security/ ×3
- http://b.hatena.ne.jp/entrylist?sort=hot&of=50&thr... ×3
- http://d.hatena.ne.jp/ockeghem/searchdiary?word=SQ... ×3
- http://reader.livedoor.com/subscribe/http://www.to... ×3
- http://www.devnull.jp/tdiary/20070907.html ×3
- http://d.hatena.ne.jp/monjudoh/20070807/1186505259... ×3
- http://b.hatena.ne.jp/ockeghem/ ×3
- http://b.hatena.ne.jp/kazuhooku/sql/?mode=detail ×3
- http://www.tokumaru.org ×3
- http://bloger.x0.com/result/アップローダー/画像アップローダー ×3
- http://b.hatena.ne.jp/t/SQL Injection ×3
- http://b.hatena.ne.jp/ockeghem/imagefight/ ×3
- http://b.hatena.ne.jp/entry/5892458 ×3
- http://d.hatena.ne.jp/ikepyon/ ×3
- http://labs.cybozu.co.jp/blog/kazuho/ ×3
- http://labs.cybozu.co.jp/blog/takesako/2007/08/lls... ×3
- http://labs.ceek.jp/hbnews/list.cgi ×3
- http://b.hatena.ne.jp/no_ri/SQL Injection/ ×3
- http://search.live.com/spresults.aspx?q=とりうる ×2
- http://b.hatena.ne.jp/entrylist?sort=hot&of=150&th... ×2
- http://b.hatena.ne.jp/ockeghem/bmp/ ×2
- http://b.hatena.ne.jp/t/mod_imagefight?sort=eid ×2
- http://b.hatena.ne.jp/t?tag=mysql&of=25&sort=hot&t... ×2
- http://d.hatena.ne.jp/teracc/20070808 ×2
- http://blog.chew.jp/result/sql データベース名/sql データベース名... ×2
- http://b.hatena.ne.jp/keyword/TCP/IP ×2
- http://b.hatena.ne.jp/entrylist?url=http://&thresh... ×2
- http://b.hatena.ne.jp/ockeghem/oracle/?mode=detail... ×2
- http://clip.livedoor.com/clips/escape_artist/tag/S... ×2
- http://b.hatena.ne.jp/t/mod_imagefight ×2
- http://www.about-reference.com/db/mysql-manual/str... ×2
- http://r.hatena.ne.jp/pero1/セキュリティ/?of=30 ×2
- http://b.hatena.ne.jp/t/SQL injection ×2
- http://erokey.ddo.jp/diary2/AV女優/20070901.html ×2
- http://b.hatena.ne.jp/t/mysql ×2
- http://d.hatena.ne.jp/tessy/?of=15 ×2
- http://nogue.cocolog-nifty.com/diary/2007/05/refiz... ×2
- http://www.math.sansu.org/u/diary/?date=200706 ×2
- http://b.hatena.ne.jp/entrylist?sort=hot&of=200&th... ×2
- http://d.hatena.ne.jp/ockeghem/20071021 ×2
- http://tokumaru.org/d/20070614.html ×2
- http://www.0048.com/ ×2
- http://d.hatena.ne.jp/ikepyon/20080919 ×2
- http://b.hatena.ne.jp/t/tkmr ×2
- http://www.math.sansu.org/u/diary/?date=20070529 ×2
- http://d.hatena.ne.jp/tessy/20070902 ×2
- http://search.live.com/results.aspx?q=postgresql言語... ×2
- http://bookmark.fc2.com/search/tag/xss ×2
- http://nihongo.homeip.net/word/サニタイズ/ ×2
- javascript break ×15 / 脆弱性 画像 script ×9 / mod_imagefight ×8 / 画像 xss ×8 / pg_escape_string ×7 / IEEE754 ×7 / 徳丸浩 ×6 / 徳丸 浩 ×4 / JavaScriptを埋め込んだ画像 ×4 / php mysql sqlインジェクション 対策 推奨 方法 ×4 / SQLインジェクション バインド変数 ×4 / oracle 暗黙の型変換 ×4 / XSS JavaScript ×4 / XSS ×4 / 画像 XSS ×4 / png 動画 ×4 / シングルクォート postgresql 暗黙の型変換 ×3 / SQLインジェクション 防ぐ 難しい JavaScript ×3 / apache gif サニタイジング ×3 / JavaScript XSS 対策 ×3 / IE限定 javascript タグ 画像 ×3 / IEEE-754 整数 ×3 / ウェブアプリケーションセキュリティ 書評 ×3 / doubleで表現できない整数 ×3 / SQLインジェクション 数値 ×3 / sql 数値 クオート ×3 / SQL 暗黙の型変換 ×3 / キーワード不明 ×3 / javascript for break ×2 / break ラベル ×2 / sql インジェクション XSS CSRF ×2 / ruby 多重ループ ×2 / SQLインジェクション 置き換え Perl ×2 / sqlインジェクション 対処法 ×2 / 仮数部 すべて1 ×2 / FizzBuzz問題 ×2 / ORA-01722 UPDATE ×2 / php 整数の範囲 ×2 / sql 数値変数 ×2 / sql update シングルクォート ×2 / sql where 数値 ×2 / oracle シングルクォート ×2 / XSS GIF ×2 / mysql 暗黙の型変換 ×2 / pg_escape_string 数値に ×2 / XSS 画像 ×2 / php oracle sqlインジェクション対策 ×2 / oracle SQL インジェクション エスケープ ×2 / Oracle UPDATE ORA-01722 エラー ×2 / SQL injection 対策 関数 ×2 / プログラム書法 ×2 / sql 変数 ×2 / postgresql 数値 クォート ×2 / パラメータ 妥当性 チェック ×2 / postgres 暗黙の型変換 ×2 / どうしてプログラマに・・・プログラムが書けないのか? ×2 / sql 数字項目 ×2 / sql 型変更 ×2 / jumper 金床 ×2 / imagemagic javascript ×2 / sqlインジェクション postgresql 数値 比較 ×2 / エンディアン bm ビッグ ×2 / Oracle 暗黙の型変換 ×2 / ORA-01722 明示的な変換 ×2 / javascriptエスケープ 金床 ×2 / IEEE754 形式 ×2 / PHP SQL シングルクォート ×2 / web 入力値検証 ×2 / JAVASCRIPT case BREAK文 ×2 / sql 文字列リテラル 変換 ×2 / xss テスト ×2 / そろそろ 一言いっとくか ×2 / gif XSS ×2 / postgresql 数値チェック ×2 / oracle sql インジェクション 対策 ×2 / SQL 暗黙 型変換 ×2 / sql文 変数 ×2 / SQL文 データ型変換 ×2 / Perl 数値型 確認 ×2 / SQL ORA-01722 ×2 / SQLインジェクション 実験 ×2 / 徳丸 セキュリティ ×2 / pg_escape_string インジェクション ×2 / Postgresql バインド機構 ×2 / php 画像 xss ×2 / SQL文 型変換 ×2 / セレクトボックスの値を受け取る javascript ×2 / ORA-01722 ×2 / oracle sql エスケープ インジェクション ×2 / oracle シングルクォート エスケープ ×2 / 暗黙的な変換 ora ×2 / sql 数値型 型変換 ×2 / oracle 暗黙変換 パラメータ ×2 / SQLインジェクション CSRF XSS ×2 / SQL 文字列 数値 比較 自動変換 ×2 / "%" "_" pg_escape_string エスケープ ×2 / VARCHAR2型 推奨 ×2 / sql インジェクション 対策 ×2 / XSS対策 ×2 / PostgreSQL 暗黙の型変換 ×2
| SQLインジェクション対策はおすみですか? 開発開始時点からのコンサルティングから、公開済みWebサイトの脆弱性検査、 脆弱性発見後の適切な対策まで |