SQLインジェクション

SQLインジェクションってどういう攻撃なんだろう。
プレースホルダって何?


今回は、みなさんお馴染みのSQLインジェクションについて、わかりやすく解説します。

本記事では、SQlインジェクションの具体的な攻撃例、対策について初学者向けに解説しています。

情報処理試験でSQLインジェクションについて勉強している方も必見です。

攻撃内容

SQLインジェクションとは、攻撃者が入力欄にSQLを入力して、サーバに送信(リクエスト)することで、サーバ側で攻撃者が入力したSQLを実行してしまう攻撃です。

通常、クライアントが入力した情報をもとにサーバ側でSQLを組み立てて、実行することで、対象のDBから値を取得したり、DBにレコードを追加・削除・更新したりします。


攻撃例

攻撃例は以下の通りです。

まず、ユーザ検索をするような検索フォームに、以下の値を攻撃者が入力します。

以下、入力値のことをリテラルと呼びます

' or '--' = '--


サーバ側で用意しているSQLは次のようになっているとします。

SELECT * FROM user WHERE id = 'リテラル';


攻撃者がリクエストした「文字列リテラル」をSQLに当てはめると、以下になります。

SELECT * FROM user WHERE id = '' or '--' = '--';



すると、本来は利用者が入力したid名でuserテーブルにある情報を取得してくるはずが、

「’–‘ = ‘–‘」がtrueになることで、userテーブルにあるユーザ情報全てを取得する命令に変わってしまっています。


このように、予期せぬSQLを実行されないためには、どうしたらいいでしょう。


対策

サーバ側でSQLを組み立てる時に、入力値をそのままSQLに入れないようにします。

①SQL文を組み立てる時にプレースホルダを使う

プレースホルダとは、SQLの雛形の中に変数の場所を表す記号です。
下記の?がプレースホルダに当たります。

SELECT * FROM user WHERE id = ?


プレースホルダへ実際の値を機械的な処理で割り当てます。

例えば、Javaの場合は以下のようにコーディングしておき、プレースホルダにセットします。

PreparedStatement prep = conn.prepareStatement("SELECT * FROM user WHERE id = ?");
prep.setString(1,"リテラル");


プレースホルダを利用することで、プレースホルダ以外の部分は完全に固定化されます。

攻撃者がどのような入力をしてきても、文字列としか見なさないため、攻撃者の入力をSQLとして実行することがありません。


先ほどの攻撃者の入力を、プレースホルダに当てはめると、単なる文字列になっていることがわかります。

SELECT * FROM user WHERE id = "' or '--' = '--";



入力された値をプレースホルダに割り当てることを「バインド」と言います。


プレースホルダには、2種類あります。

  1. 静的プレースホルダ:SQLの組み立てをDB側で行う
  2. 動的プレースホルダ:SQLの組み立てをアプリケーション側で行う


一般的に、静的プレースホルダはSQLが後から変化することがないため、安全です。



②ウェブアプリケーションに渡すパラメータにSQL文をそのまま指定しない

SQLをhiddenパラメータで指定しているという事例がありました。

hiddenパラメータは一見ブラウザ上に表示されないように見えますが、ブラウザの開発者ツールを使えば簡単に改ざんできます。

hidddenパラメータに直接SQLを入れておくなんて、ぶっ飛んだ実装だね



③エラーメッセージをそのままブラウザに表示しない

エラーメッセージの中には、実行されたSQLやデータベースの情報を表示する場合があります。

その場合、攻撃者に有益な情報を与えることにつながります。