SQLインジェクション
SQLインジェクションの例
ログインフォームに入力されたユーザIDとパスワードでユーザを認証するアプリケーションがあり、アプリケーションの内部では次のようにSQL文を作成しています
ここで攻撃者がログインフォームにユーザIDとして「myid」、パスワードとして「>pass’ OR ’a’=’a」を入力した場合、結果としてDBに対して次のクエリーが発行されます。

このクエリーは 'OR' 以降の条件が常に真であるため、すべてのレコードがWHERE句の条件に該当するようになり、不正なパスワードを入力していても認証されてしまいます。
そのほかに、DELETE文によるデータの削除、テーブル名やカラム名といったスキーマ情報の取得などの不正操作が行われるケースもあります。
SQLインジェクションの対策
コーディングによる対策
SQLインジェクションを防ぐには、ユーザーの入力データを検証してSQLクエリーで意味を持つメタ文字を適切にエスケープすることや、プリペアド ステートメントの使用が有効です。例えば、これらをコーディング規約として定義すること、コードレビューの観点に追加することが想定されます。
- 入力データをSQLクエリに組み込む前に入力データの安全性を検証する
- SQLクエリをパラメーター化する
- SQLメタ文字のエスケープ処理を行う

プレースホルダ「 ? 」で表されるパラメータは常に文字列として解釈されるため、入力データがSQL文の一部として扱われることはありません。
そのほかに、攻撃者に手がかりを与えないよう、データベースからの詳細なエラーメッセージをユーザに表示しない、また必要最小限の権限でデータベース操作を行うといった対策も挙げられます。
ただし、このような対策を行ったとしても大規模なアプリケーションで複数のクラス・メソッドにまたがるソースコードに潜む全て問題を従来の目視レビューだけで発見するのは不可能に近いとも言えます。
そこで、静的解析ツールでコードレビューを自動化して機械的にソースコードの問題を検出するようにします。
静的解析ツールJtestでSQLインジェクションを検出する
Parasoft Jtest にはSQLインジェクションが発生するコードを検出する静的解析ルールがあります。- SQL インジェクションから防御する [BD.SECURITY.TDSQL]
- createStatement ではなく prepareCall または prepareStatement を使用する [SECURITY.IBA.UPS]
SQLインジェクションから防御する [BD.SECURITY.TDSQL]
このルールは、不正な文字を含んでいる可能性のある入力データが、検証メソッドによるチェックを受けないまま出力SQLメソッドに渡されている場合に違反をレポートします。
検出例 - Jtest 解析結果とソースコード:

Example.javaの7, 8行目でアプリケーションを操作するユーザーが入力したデータを取得し、11 行目でデータベースの操作を行う Example_sql.java の exec_sql() メソッドにユーザーが入力したデータを渡します。
Example_sql.java ではSQLクエリの作成に exec_sql() メソッドに渡されたデータをそのまま利用、クエリを発行します。
ユーザーがユーザー名とパスワードとして文字列 ' or ''=' を使用した場合、生成されるクエリは次のようになります。
SELECT user_id, user_class, rights FROM users WHERE user_name = '' or ''='' and password = '' or ''=''
攻撃者は必要な認証情報を入力しなくてもユーザーテーブルの 1 番目のユーザーとして認証されます。
この SQL クエリを利用するとすべてのユーザー情報を取得することができます。
修正例 - ソースコード:
ユーザーが入力したデータを使用する前に検証します。

ユーザーが入力したデータを文字列長のチェックやエスケープ処理を行う validate() メソッドを経由させることでSQLクエリには安全な文字列だけが含まれるようにします。
Jtestの「SQLインジェクションから防御する [BD.SECURITY.TDSQL]」ルールでソースコードを解析することにより、 SQLインジェクションによる攻撃に対して脆弱なコードを発見し、改修することが可能になります。
createStatement ではなく prepareCall または prepareStatement を使用する [SECURITY.IBA.UPS]
このルールは、java.sql.Connection インターフェイスの createStatement メソッドが使用されているコードに違反をレポートします。
検出例 - Jtest 解析結果とソースコード:

createStatement を利用してユーザーが入力したデータを使用して直接SQLクエリ作成しています。
この場合、ユーザが ' or ''=' などの悪意のあるコードを入力した場合、SQLクエリを利用して全てのユーザー情報を取得することができます。
修正例 - ソースコード:

createStatement メソッドの代わりに prepareStatement メソッドを使用してSQLクエリをパラメータ化します。
さらに、setString メソッドをしようすることでユーザーが入力したデータは自動的にダブルクォーテーションでくくられるため、SQLインジェクションによる攻撃に予防することもできます。
このように createStatement が使用されている箇所を検出し、prepareStatement に変更すべきかどうかを検討したい場合、Jtest の「createStatement ではなく prepareCall または prepareStatement を使用する [SECURITY.IBA.UPS]」ルールを使うと便利です。
Jtestが検出する脆弱性(抜粋)一覧
- クロスサイト スクリプティング(XSS)
- SQLインジェクション (本ページ)
- HTTPレスポンス分割
- さまざまなリソースインジェクション
※ 本ページでご紹介した「SQL インジェクションから防御する [BD.SECURITY.TDSQL]」と「createStatement ではなく prepareCall または prepareStatement を使用する [SECURITY.IBA.UPS]」ルールを含むセキュリティルール及びセキュリティコンプライアンス規約セットによる静的解析には「セキュリティコンプライアンスパック」のライセンス(有償)が必要です。
イベント・セミナー
Java対応静的解析・単体テストツール Jtestに
関するお問い合わせ
テクマトリックス株式会社
東京本社ソフトウェアエンジニアリング事業部
03-4405-7853
- メールでのお問い合わせ
- parasoft-info@techmatrix.co.jp