SQLインジェクション
SQLインジェクションとは
SQLインジェクションは、Webアプリの入力欄などに細工した文字列を送り込み、アプリが組み立てる SQL 文の意味を書き換えてデータベースを不正に操作する攻撃です。[[Webセキュリティ]] の脆弱性の中でも、情報漏えい事故の原因として特に有名です。
成功すると、会員情報の全件取得、データの改ざん・削除、認証の突破(ログイン画面のすり抜け)など、[[リレーショナルデータベース]] に対して深刻な被害が発生します。
なぜ起きるのか
原因は、ユーザーの入力値を [[SQL]] 文に文字列連結でそのまま埋め込む実装にあります。
// 危険な例: 入力値をそのまま連結している
const sql = "SELECT * FROM users WHERE name = '" + userInput + "'";
この書き方では、入力値に ' などの記号を含めると SQL 文の構造そのものが変わってしまい、開発者が意図しない命令として解釈されます。「データのつもりの文字列が、命令として実行される」ことが本質です。
対策の基本
- プレースホルダ(バインド機構)を使う: SQL 文の「型」と「値」を分けて渡す仕組みで、値が命令として解釈されなくなります — 最も基本で確実な対策です
- [[ORM]] を使う: 内部でプレースホルダを使って SQL を組み立てるため、通常の使い方なら安全側に倒れます
- 最小権限の DB ユーザーで接続する: アプリ用アカウントに削除や管理系の権限を与えない([[最小権限の原則]])。DBユーザーの作り方と権限の絞り込みは [[データベースのユーザーと権限管理]] が扱います
- エラーメッセージを画面に出さない: DB のエラー詳細は攻撃者へのヒントになります
- [[WAF]] — 既知の攻撃パターンを通信段階で遮断する補助策
// 安全な例: プレースホルダを使う
db.query('SELECT * FROM users WHERE name = ?', [userInput]);
初学者向けポイント
- 「SQL は文字列連結で組み立てない。必ずプレースホルダ」— これだけでほとんどの SQL インジェクションは防げます
- 入力チェック(バリデーション)は大切ですが、それだけに頼るのは危険です。プレースホルダと併用します
- ORM を使っていても、生 SQL を書く機能で文字列連結すれば同じ穴が開きます
関連技術とのつながり
- [[SQL]] — 攻撃対象となる言語そのもの。文の構造を知ると原理が理解できる
- [[リレーショナルデータベース]] — 被害を受けるデータの保管場所
- [[ORM]] — 正しく使えばプレースホルダを自動で適用してくれる
- [[WAF]] — アプリ側の対策を補う通信段階の防御
- [[最小権限の原則]] — 万一突破されたときの被害を最小化する考え方
- [[プロンプトインジェクション]] — 同じ本質をLLMで起こす攻撃。こちらは分離が原理的に難しい
Q: SQLインジェクションの最も基本的な対策はどれ?
- [ ] 通信をHTTPSにする
- [x] プレースホルダ(バインド機構)を使ってSQLを組み立てる
- [ ] データベースを毎日バックアップする
解説: プレースホルダは SQL の型と値を分離するため、入力値が命令として解釈されなくなります。
Q: SQLインジェクションが起きる直接の原因はどれ?
- [x] 入力値を文字列連結でSQL文にそのまま埋め込むこと
- [ ] データベースの容量不足
- [ ] パスワードの使い回し
解説: 入力値の連結によって SQL 文の構造が書き換えられることが原因です。
Q: アプリ用のDBアカウントに管理系権限を与えない目的はどれ?
- [ ] SQLの実行速度を上げるため
- [x] 攻撃が成功した場合の被害を最小限に抑えるため
- [ ] エラーメッセージを見やすくするため
解説: 最小権限の原則に基づき、万一侵入されても削除や設定変更などの深刻な操作をさせないためです。