📌 本記事のターゲット
- プログラミング初学者・Web開発を学び始めたばかりの方
- 「SQLインジェクションという言葉は聞いたことがあるけれど、具体的に何が起きるのかわからない」という方
- 難しいセキュリティ専門用語を使わずに、仕組みと対策をざっくり理解したい方
🎯 結局この記事で何が言いたいのか?
「ユーザーが入力した文字を、そのままSQLの文字列と合体させてはいけない」
SQLインジェクションとは、悪意のあるSQLの命令をデータベースに『注入(インジェクション)』されてしまう攻撃です。
これに対抗するための最も基本の対策は 「プレースホルダ(バインド変数)」 を使うことです。
1. SQLインジェクションとは
SQLインジェクションを一言でいうと、「悪意のある入力によって、開発者が意図しないSQLが勝手に実行されてしまう脆弱性」のことです。
🚨 もし攻撃が成功するとどうなる?
- データの流出: データベース内の個人情報やパスワードがすべて盗まれる
- データの改ざん・削除: データベースのデータが丸ごと消去される
- 不正ログイン: 管理者権限を乗っ取られてログインされる
2. なぜ起きる?(悪いコードの例)
ユーザーが入力したID(inputId)を使って、データベースから会員情報を検索する以下のようなJavaのコードを例に考えてみましょう。
⚠️ 悪いコード(文字列結合)
// ❌ ユーザーの入力をそのままSQL文の文字列と合体させている
String sql = "SELECT * FROM users WHERE user_id = '" + inputId + "'";
もし、悪意のあるユーザーが画面の入力欄(inputId)に、以下のような怪しい文字列を入力したらどうなるでしょうか?
' OR '1' = '1
この入力値がそのままプログラムに組み込まれると、実際にデータベースへ送られるSQLは以下のようになります。
SELECT * FROM users WHERE user_id = '' OR '1' = '1'
データベースはこのSQLを見て下記のように解釈します。
「user_id が空、または、1は1と等しい(常に正しい) データを全部持ってきて!」
結果、条件式全体が「常に真(正しい)」になってしまうため、登録されている全ユーザーの情報が画面に表示されてしまうのです。これがSQLインジェクションの正体です。
3. どう防ぐ?(正しいコードの例)
防ぎ方はシンプルです。SQLの「命令(骨組み)」と「データ(値)」を明確に分けてデータベースに送る 「プレースホルダ(バインド変数)」 を使います。
⭕️ 正しいコード(プレースホルダの使用)
// 1. 値を入れたい場所を「?」にして、先にSQLの骨組みを作る
String sql = "SELECT * FROM users WHERE user_id = ?";
PreparedStatement stmt = connection.prepareStatement(sql);
// 2. 「?」の部分に、安全にデータを流し込む
stmt.setString(1, inputId);
なぜこれで防げるの?
?(プレースホルダ)を使うと、データベースは先に「このSQLは、user_id が一致するデータを1件だけ探す命令だな」とSQLの構造を確定させます。
そのあとにどんなに怪しいデータ(例:' OR '1' = '1)が送られてきても、データベースはそれを命令の一部ではなく、ただの 「' OR '1' = '1 という名前の文字列データ(値)」 として処理します。
そのため、SQLの命令がねじ曲げられて実行されることは絶対にありません。
💡 補足:フレームワーク(Spring Boot等)の場合
「毎回これを手動で書くのは大変そう…」と思うかもしれませんが、Spring Boot などのライブラリを使っていれば、裏側で自動的にこのプレースホルダが使用される仕組みになっています。
ただし、SQLを自分で組み立てるようなネイティブクエリを記述する際は、文字列結合をしてしまわないように細心の注意を払いましょう。
4. まとめ
SQLインジェクションは、Webアプリ開発において絶対に防がなければならない重大な脆弱性です。
- SQLインジェクションは、悪意のあるSQLを勝手に実行されてしまう攻撃
- 対策は「プレースホルダ(バインド変数)」の利用が基本中の基本
- モダンなフレームワークを使っている場合も、仕組みを理解して過信しすぎない