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種類あります。
- 静的プレースホルダ:SQLの組み立てをDB側で行う
- 動的プレースホルダ:SQLの組み立てをアプリケーション側で行う
一般的に、静的プレースホルダはSQLが後から変化することがないため、安全です。
②ウェブアプリケーションに渡すパラメータにSQL文をそのまま指定しない
SQLをhiddenパラメータで指定しているという事例がありました。
hiddenパラメータは一見ブラウザ上に表示されないように見えますが、ブラウザの開発者ツールを使えば簡単に改ざんできます。
hidddenパラメータに直接SQLを入れておくなんて、ぶっ飛んだ実装だね
③エラーメッセージをそのままブラウザに表示しない
エラーメッセージの中には、実行されたSQLやデータベースの情報を表示する場合があります。
その場合、攻撃者に有益な情報を与えることにつながります。