SQLインジェクションとは
アプリケーションのセキュリティ上の不備を意図的に利用し、アプリケーションが想定しないSQL文を実行させることにより、データベースシステムを不正に操作する攻撃方法のこと、また、その攻撃を可能とする脆弱性のことです。
SQLに別のSQL文を「注入(inject)」されることから、「ダイレクトSQLコマンドインジェクション」もしくは「SQL注入」とも呼ばれます。
アプリケーションが入力値を適切にエスケープしないままSQL中に展開することによりで発生します。
次のようなSQLが発行されることを前提に説明します。
SELECT * FROM users WHERE name = '(入力値)';
ここで入力値に "1' OR '1' = '1" という文字列を与えた場合を考えると、SQL文は次のように展開されます。
SELECT * FROM users WHERE name = '1' OR '1' = '1';
上記のSQL文では条件が常に真となるため、nameカラムの値にかかわらず、レコードが全件取得できてしまいます。このような攻撃は、入力値が1つだけのものに限りません。
また、これを応用してSELECTの条件式にデータベース内の情報を確認するようなサブクエリーを含ませ、その抽出の成否によって本来参照することのできないデータベース内の情報(テーブル名など)を知ることができる、ブラインドSQLインジェクションと呼ばれる手法も存在する。
また、複数のSQL文を注入することによるデータの破壊や改竄、ストアドプロシージャを実行させ、情報の漏洩や改竄、OSコマンドの実行などを引き起こすこが可能のる場合があります。
対策
- 型を指定する
- 静的プレースホルダの利用する
- 発行するsql文の中で文字列展開をしない
- 文字エンコーディングを指定する
- 入力値に対してのチェックを行う
Javaでの静的プレースホルダ実装例
import java.sql.PreparedStatement;
public class Main {
public static void main(String[] args) {
/**
* 省略
*/
stmt = conn.prepareStatement("SELECT name, secret FROM users WHERE user = 'true' AND name = ? AND password = ? ");
stmt.setString(1, name);
stmt.setString(2, password);
rs = stmt.executeQuery();
}
}