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’ というパラメータを渡している。このように OR で 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

Article written by

コメントを残す