SQLインジェクション脆弱性への対策について

SQLインジェクションについて,対策方法を勉強したので忘れないようにメモしておく。

SQLインジェクションとは

データベースと連動したWebサイトで,データベースへの問い合わせや操作を行うプログラムにパラメータとしてSQL文の断片を与えることにより,データベースを改ざんしたり不正に情報を入手する攻撃。また,そのような攻撃を許してしまうプログラムの脆弱性のこと。

具体例

例えば,ユーザによって入力されたユーザID,パスワードをそれぞれ{$userId}{$passwd}に代入し,SQLでその存在が確認できればログインできるWEBページがあるとする。

そのWEBページで使われているSQLは以下のようになっている。

SELECT * FROM ユーザマスタ WHERE ユーザID = '{$userId}' AND パスワード = '{$passwd}'

悪意のあるユーザがユーザID「dog」としてパスワードを入力せずにログインを試みるようなパラメータを入力した際には,以下のようなSQLとなる。

SELECT * FROM ユーザマスタ WHERE ユーザID = 'dog' AND パスワード = '' OR 'A' = 'A'

$passwdに対して‘ OR ‘A’ = ‘A’というパラメータを渡している。このようにAはAである,というような条件式を追加することで不正にログインすることが出来てしまう。

SQLインジェクション脆弱性への対策方法

SQLインジェクション脆弱性への対策としては,プレースホルダを使用することが挙げられる。ここでパラメータ部分を示す記号「?」のことをプレースホルダと呼び,そこへ実際の値を割り当てることを「バインドする」と呼ぶ。

プレースホルダには,以下の2つがある。

  • 静的プレースホルダ
  • 動的プレースホルダ

以下,これらについて説明する。

静的プレースホルダ

静的プレースホルダは,JIS/ISOの規格では「準備された文(Prepared Statement)」と規定されている。これは,プレースホルダのままのSQL文をデータベースエンジン側にあらかじめ送信して,実行前に,SQL文の構文解析などの準備をしておく方式である。SQL実行の段階で,実際のパラメータの値をデータベースエンジン側に送信し,データベースエンジン側がバインド処理を行う。つまり,SQL文の構文がバインド前に確定する。このことから,セキュリティの観点で,静的プレースホルダは最も安全である。静的プレースホルダでは,SQLを準備する段階で SQL文の構文が確定し,後からSQL構文が変化することがないため,パラメータの値がリテラルの外にはみ出す現象は起きない。その結果として,SQLインジェクションの脆弱性が生じることはない。

動的プレースホルダ

動的プレースホルダとは,プレースホルダを利用するものの,パラメータのバインド処理をデータベースエンジン側で行うのではなく,アプリケーション側のライブラリ内で実行する方式である。動的プレースホルダは静的プレースホルダとは異なり,バインド処理を実現するライブラリによっては,SQL構文を変化させるようなSQLインジェクションを許してしまう,脆弱な実装のものが存在する可能性を否定できない。
よって,SQLインジェクション脆弱性対策には,なるべく静的プレースホルダを使用することを推奨する。

プログラミング言語とデータベースの組み合わせによって使用されるプレースホルダの種類が分かれる

プログラミング言語とデータベースの組み合わせでデフォルトで使用されるプレースホルダが静的プレースホルダか,動的プレースホルダかに分かれる。

以下にプログラミング言語とデータベースの組み合わせでどちらのプレースホルダが使われるかを示す。

Java + Oracle

項目内容
プレースホルダの実装静的のみ
デフォルトで使用されるプレースホルダ静的
 

Java + MySQL

項目内容
※静的プレースホルダを使用するには,DB接続時に`useServerPrepStmts=true`というパラメータを指定する必要がある。
プレースホルダの実装静的または動的
デフォルトで使用されるプレースホルダ動的
 

PHP + MySQL

項目内容
※静的プレースホルダを使用するには,DB接続時に`PDO::setAttribute(ATTR_EMULATE_PREPARES, false)`というパラメータを指定する必要がある。
プレースホルダの実装静的または動的
デフォルトで使用されるプレースホルダ動的
 

PHP + PostgreSQL

項目内容
プレースホルダの実装静的のみ
デフォルトで使用されるプレースホルダ静的
 

Perl + MySQL

項目内容
※静的プレースホルダを使用するには,DB接続時に`mysql_server_prepare=1`というパラメータを指定する必要がある。
プレースホルダの実装静的または動的
デフォルトで使用されるプレースホルダ動的
 

ASP.NET + SQL Server

項目内容
プレースホルダの実装静的のみ
デフォルトで使用されるプレースホルダ静的
 

まとめ

  • SQLインジェクション脆弱性への対策にはプレースホルダを使う
  • 動的プレースホルダよりも,なるべく静的プレースホルダを使うことが望ましい

参考
SQLインジェクション
安全なSQLの呼び出し方
PDOでATTR_EMULATE_PREPARESを適切に設定してないとSQLインジェクションの原因になるかも(MySQL編)
プリペアド・ステートメント(プレースホルダ)入門
PDOにおける一応の安全宣言と残る問題点 | 徳丸浩の日記
SQLインジェクションのまとめ – No Programming, No Life