第10章 著名な脆弱性対策
SQL注入攻撃対策

SQL注入

SQL注入は、プログラムがパラメータを埋め込んでSQL文を組み立てる場合に、攻撃者がそのパラメータに特殊記号(記号)を含ませたSQLコマンドを与えることで、データベースの不正操作が可能となる脆弱性、またはその脆弱性に対する攻撃をいう。

SQL注入攻撃の対策について、重要となるポイントを中心に以下に記述する。詳細については、Webアプリケーション編の第6章 入力対策「SQL注入」を参照されたい。

SQL注入
図10-11: SQL注入

SQL注入対策

SQL注入攻撃を成立させないようにする対策には次の4つが考えられる。

(1) 入力検査

プログラムに渡された値が正しい形式であるかどうかを厳密に検査することによって、攻撃パターンの侵入を防ぐものである。

文字種、桁数等が限定されているデータ項目については高い効果が期待できる。ただし、「任意の長さの通信文」のように文字種や桁数を限定できないデータ項目はその限りでない。

(2) 特殊記号対策

文字列定数 '...' 中に入り込むとSQL文の構文が改変されるおそれのある特殊記号を無害化するか、排除するものである。SQL文では多くの記号が使われるが、とくに対処が必要なのは次の3種類である。

  1. シングルクォート「'」
  2. セミコロン「;」 (一部のデータベースエンジンにおいて)
  3. 逆スラッシュ(円記号)「\」 (一部のデータベースエンジンにおいて)

シングルクォート「'」と逆スラッシュ「\」は、それぞれ「''」「\\」のように各文字を2個並べることによって、文字列定数 '...' の中で特殊な意味を持たないようにすることができる。

セミコロン「;」は、この記号がそのままSQL文の構文の中に埋め込まれてマルチプルステートメントが構成されることを防ぐ必要がある。

(3) プリペアドステートメントの利用

プリペアドステートメントを用いると、文字列連結演算を用いることなくSQL文の構文の中に値を埋め込むことができる。この方法には、ほかに「プレースホルダ」「変数バインド」等の呼び方もある。

次のようなステップでSQL文への値の埋め込みと実行を行う。

  1. 埋め込む値が確定しないまま、SQL文の原型をプリペアドステートメントのソースコードとして記述する。値を埋め込む場所にはプレースホルダ(「?」「$3」等)を記述しておく
  2. プリペアドステートメントの文字列をコンパイルする(構文が確定する)
  3. 各プレースホルダに対応する値を与える
  4. コンパイル済のプリペアドステートメントを実行させる

ここで注意しておきたいこととして、プリペアドステートメントのソース文字列の中にユーザ入力データを組込むと、せっかくの対策効果が台無しになるということが挙げられる。

(4) ストアドプロシジャによる実装

アプリケーション側でSQL文の文字列を組み立てずに済ませるもうひとつの方法として、DBアクセスをすべてストアドプロシジャ呼出しで実装するというやり方がある。

アプリケーションで必要となるDBアクセスパターンごとに、DBエンジン側にストアドプロシジャを用意し、アプリケーションからはこれらのプロシジャにパラメータを渡すというものである。ストアドプロシジャ用のプログラミング言語の中で、SQLの構文とパラメータ要素が明確に識別され処理されるため、SQL文の構文が変えられることはほとんどないと期待される。

対策を損なうもの

(1) エスケープ処理の効果を損なうもの

シフトJIS、UTF-8等のマルチバイト文字コードが使われる場面では、エスケープ処理に支障が生じることがある。

次の対策が必要である。

(2) プリペアドステートメントの効果を損なうもの

処理系によってはプリペアドステートメントの実装が不十分な場合がある。APIの内部で特殊記号のエスケープ処理を行うことによって動作を模擬しているようなケースである。そして、そのエスケープ処理が十分でないことが考えられる。

プリペアドステートメントによる対策方法を採用する際、データベースエンジン側でSQL文ソースコードが処理されてSQL文の構文が確定することを確認する。プリペアドステートメントの実装が十分でなければ、アプリケーション側で特殊記号対策を行う。

まとめ

SQL注入攻撃の対策には、次の4つがある。入力検査、特殊記号対策、プリペアドステートメントの利用、ストアドプロシジャによる実装である。採用を考慮する順序は、ストアドプロシジャ、プリペアドステートメント、特殊記号対策の順である。入力検査は常に行う。