はじめに
SQLインジェクションというワードには馴染みがありましたが具体的な内容と対策についてはよくわかっていないので簡単にまとめてみました。間違い等あればご指摘いただけるとありがたいです!
SQLインジェクションとは
SQLインジェクションとは悪意のあるユーザが例えば入力フォームなどにSQL文を入力することでDBを不正に操作する攻撃手法です。
どういう操作で起きるのか
例えばユーザ名とパスワードを入力してログインするようなログイン機能があったとします。
また、そのログイン処理は、DBに該当するユーザIDとパスワードのユーザがいればログインできるという仕様だと仮定します。具体的には以下のようなSQL文で表現できます。
String sql = "SELECT * FROM users WHERE username ='userName' AND password ='pasword' ";
このSQLが実行される時に、もし、ユーザIDにtanaka、パスワードにaaa’ or ‘1’=’1と入力した場合は以下のようになります。
String sql = "SELECT * FROM users WHERE username ='tanaka' AND password ='aaa’ or ‘1’=’1’ ";
この時には1=1は必ず満たされるので、パスワードがわからなくても特定のユーザIDでログインすることができてしまいます。ログインできてしまうと、その後の個人情報の流出や改ざんなどもできてしまいます。
SQLインジェクションの具体的な対策
次に具体的な対策についてまとめます。
バリデーションを設ける
SQLインジェクションでは、'を入力することによってSQL文を入力することができてしまうので、半角英数字しか入力できないなどのバリデーション機能を設けることでSQLインジェクションを防ぐことができます。
//半角英数字のみ入力を許可するバリデーション
@Pattern(regexp = "^[a-zA-Z0-9]+$");
プレースホルダを使用する
プレースホルダーとは
恥ずかしながらプレースホルダーというワードを初めて聞いたので調べてみました。
プレースホルダーとは変数を?や:で置き換えて、不正な値(特殊文字など)が入力された際にSQLが実行されないようにする仕組みだそうです。具体的には以下のような処理になります。
String sql = "SELECT * FROM users WHERE username = ? AND password = ?";
//DBと接続する
//パラメータ付きSQL文をデータベースに送るための準備(PreparedStatementオブジェクトを生成)。
PreparedStatement statement = connection.prepareStatement(sql);
//作成したSQLに対して、usernameとpasswordをセットする
statement.setString(1, username);
statement.setString(2, password);
//SQLを実行する
ResultSet resultSet = statement.executeQuery();
プレースホルダーを使用すると、処理が以下の3段階で実行されます。
①SQL文をDBに送信して構文解析を行う。
②?に指定された値(userNameやpasswordなど)を挿入する。この時に値のチェックを行う。
③SQLを実行する。
このように3段階でsqlが実行されるので、もし仮に不正なSQLがフォームに入力されたとしても②で弾かれるのでSQLインジェクションが起きることはありません。
参考
『プロになるためのWeb技術入門』 ――なぜ,あなたはWebシステムを開発できないのか
https://blog.senseshare.jp/placeholder.html
https://kanda-it-school-kensyu.com/java-jdbc-contents/jj_ch03/jj_0302/
https://qiita.com/sudo00/items/eaa87db36007ee8b0bd5
https://www.javadrive.jp/servlet/database/index10.html