〜シングルクォート挿入〜まずは、SQLインジェクションの最も基本的な攻撃パターンであるシングルクォート「'」を使った手法のご紹介から。以下のようなテーブルがあるとする。'{$passwd}'ユーザによって入力されたユーザID、パスワードをそれぞれ{$userId}、{$passwd}に代入し、上記SQLにてその存在が確認できればログインできるWEBページがある。悪意あるユーザがユーザID「fumo」としてパスワードを入力せずにログインを試みる際に入力するパラメータは、以下のようになる。結果、生成されるSQL文は以下のようなものになる。'A'」という恒真式がORの対象になる。よって、WHERE句全体が常に真となり、パスワードを入力せずにユーザID「fumo」としてログインすることが可能となる。OR以降が常に真となるような恒真式が記述されることが重要である。〜セミコロンで分割〜さてお次は、ケース1の応用例として任意のSQL文を実行させる手法をご紹介する。ここではレコードの全件削除を例にとって説明する。攻撃手法SQL文におけるセミコロン「;」は、ステートメントを分割するデリミタである。この「;」を使って複数のSQL文を連結させることができる。利用するテーブルはケース1と同じものとして、今回は以下のようにパラメータを入力してみる。'A」さて、どんなSQLが生成されるでしょうか。これは以下のように二つのSQL文が続けて実行されることを意味する。'A'一つ目のSELECT文は実行されるが無害である。このようにパラメータに「;」を含ませることで、WHERE句を一旦終端させ、全件削除のDELETE文をさせることができる。'A'」という恒真式となるようにして、DELETE文のWHERE区を無効化している。〜コメントアウトで無効化〜更に応用例として、コメントアウト「--」を使用してパスワード入力部分のSQLを無効化する手法をご紹介する。利用するテーブルはケース1と同じものとして、以下のようにパラメータを入力してみる。」これで、以下のようなSQL文が実行される。''」の部分はコメントアウトされるので無効となり、結果としてケース2と同様に全件削除のSQL文として機能する。〜シングルクォート挿入〜さて、今度はデータを変更するパターンの攻撃についてご紹介する。利用するテーブルはケース1と同じものとして、ユーザIDと現在のパスワードおよび新しいパスワードを受け取り、データベースの更新が行われる例で考えてみる。'{$oldPasswd}'ユーザによって入力されたユーザID、旧パスワード、新パスワードをそれぞれ{$userId}、{$oldPasswd}、{$newPasswd}に代入し、上記SQLにてその存在が確認し、合致すればパスワードの変更が完了する。悪意あるユーザ「rose」が、自身のパスワード「fuga」とユーザ「admin」のパスワードを「malice」*1に書き換えを試みる際に入力するパラメータは、以下のようになる。結果、生成されるSQL文は以下のようなものになる。'admin'ユーザIDが「rose」でパスワードが「fuga」であるレコード、またはユーザIDが「admin」であるレコードを更新対象としてしまう。「admin」のパスワードが分からなくても「admin」のパスワードを変更することが可能となる。〜コメントアウトで無効化〜さて、今度はケース4の応用で全データを変更するパターンの攻撃についてご紹介する。利用するテーブル、条件はケース4と同様とし、悪意あるユーザが全ユーザのパスワードを「malice」に書き換えを試みる際に入力するパラメータは、以下のようになる。結果、生成されるSQL文は以下のようなものになる。'A'」の恒真式にしつつ、それ以降をコメントアウトしてWHERE句を無効化する。結果、全員のパスワードが「malice」に変更されてしまう。今まで見てきたSQLインジェクションの攻撃に対する回避方法・対策についてご紹介する。特殊文字のエスケープ(サニタイジング)SQL文に含まれたパラメータに対し、危険な文字列を検出し、特殊文字として認識させないように適切に置換・除去を行うエスケープ処理(サニタイジング)で対応する。エスケープ対象は処理系によって異なるが、一般的には次の通りである。エスケープ文字(\)を前に付加する「'」→「''」とシングルクォートを二つ重ねてエスケープすることで、文字列を囲むシングルクォートでなはく、シングルクォートを文字列定数として扱うようにする。このようにSQLインジェクションも特殊文字を悪用することによって行われるので、入力チェックとサニタイジングが有効である。データベースエンジンごとにSQLが独自拡張されていて、サニタイジングが必要な特殊文字が変わってくる。データベースエンジンごとに機能を持つ特殊文字をリストアップし、正しくエスケープ処理を実装する必要がある。SQL文の組み立てにバインド機構を使用する(準備済みSQLの利用)あらかじめコンパイルしたSQL文をデータベース側に持たせておき、値だけをデータベースに渡して実行させるためのDBMSの機能である。具体的にはプレースホルダと呼ばれる一般的な特殊文字を使用してSQL文の雛形を用意しておき、後で実際の値(変数)を割り当ててSQL文を完成させる。バインドメカニズム(バインド機構)、準備済みSQL文、プリペアードステートメント、パラメータクエリ(クエリの一部が変数のようになっており、その部分は実行時にバインドするクエリ)、ストアードプロシージャとも呼ばれる。これにより、入力データは数値定数や文字列定数として組み込まれるため、シングルクォートなどの特殊文字は、エスケープ処理せずとも強制的にただのパラメータ文字として認識され、SQL文の意味も改変される危険性がなくなる。入力前にコンパイルされているので、SQLインジェクションによってSQL文を変更することが不可能になる。特殊文字のエスケープよりも有効な手法であり、SQLインジェクション対策の最も有効的な方法である。セカンドオーダSQLインジェクション最後に入力データに適切にサニタイジング処理を施している場合でも攻撃が可能となるセカンドオーダSQLインジェクションについてご紹介しよう。「(2)パスワード変更機能」があるWebシステムを考える。「(1)ユーザ登録機能」では「ユーザID」と「パスワード」を入力して新たにユーザを登録する。「(2)パスワード変更機能」ではログイン後に、ログインしているユーザのパスワードを変更するもので、「旧パスワード」および「新パスワード」を入力してパスワードの変更を行う。この、「パスワード変更機能」は以下のように二つのSQL文によって実行されるものとする。'取得したユーザID'二つ目のUPDATE文で指定するユーザIDは一つ目のSQL文で取得したユーザIDを用いる。適切にサニタイジング処理が行われるものとする。セカンドオーダSQLインジェクションは、このように一度挿入されたデータが再利用されるような機能を利用して、間接的に攻撃を行う手法である。具体的には以下のようにパラメータを入力すればよい。--」、パスワード=「passwd」として新規登録する。するとシングルクォートを正しくエスケープした以下のようなINSERT文によりユーザが登録される。--」としてユーザ登録される。--」のパスワードを変更するために、例えば旧パスワード「passwd」を新パスワード「passwd2」を入力する。この入力により、以下SELECT文となり、ユーザIDをを引き当てる。'passwd'外部から受け取る値は新パスワードだけなので、新パスワードのみエスケープ処理される。--」がそのまま用いられる。--''このSQL文の末尾の「--''」の部分は無視されるため、以下の「admin」のパスワードを「passwd2」に変更するSQL文が実行されることとなる。'admin'悪意ある攻撃者はこの手法により、管理者「admin」のパスワードを自由に書き換えてしまうことが可能となる。一般のSQLインジェクション対策としては、バインド機構+サニタイジングの組み合わせが採用されているが、セカンドオーダSQLインジェクションはこれらの対策を潜り抜けて実行される。これは、SQLインジェクションを防ぐのに、外部から受け取るパラメータのみエスケープしているときに発生する。この攻撃も踏まえた正しいSQLインジェクション対策としては、文字列連結でSQL文を構築しようとするすべての箇所でエスケープ処理を適切に行う必要がある。データベースに格納済みの値ももれなく行う必要がある。@IT*1:悪意、敵意、害意という意味。»プロフィールid:fumokmm新しいNPNLです。(2)はてなブログをはじめよう!fumokmmさんは、はてなブログを使っています。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。