SQLインジェクション対策は「入力値を必ずエスケープする・プレースホルダを使う」が基本です。しかし、入力値のサニタイズに成功しているにもかかわらず攻撃が成立してしまうケースがあります。それが「二次SQLインジェクション(Second-Order SQL Injection)」——悪意あるデータをいったんデータベースに保存しておき、後から別のクエリに組み込まれることで攻撃が発動するパターンです。
この記事では、二次SQLインジェクションの仕組みを通常のSQLインジェクションと比較しながら解説し、現場で使える防御手順を紹介します。「うちはエスケープ処理を入れているから大丈夫」という思い込みを見直す機会にしてください。

二次SQLインジェクションとは?
二次SQLインジェクション(Second-Order SQL Injection)は、悪意あるSQL構文を含む入力値がいったんサニタイズされてデータベースに保存され、後でそのデータを別の処理(更新・検索・表示)に使うタイミングで実行されるインジェクション攻撃です。
通常のSQLインジェクションは「入力→即クエリ生成→実行」という流れで完結するのに対し、二次SQLインジェクションは「入力→保存→後で取り出し→クエリに組み込まれて実行」という、時間差のある二段階の流れで攻撃が完結します。
攻撃者は最初の保存段階で怪しい動作を起こさないため、WAFやログ監視での検知が難しく、「気づかないうちに仕掛けられていた」という状況になりやすいのが特徴です。
通常のSQLインジェクションとの違い
| 比較項目 | 通常のSQLインジェクション | 二次SQLインジェクション |
|---|---|---|
| 攻撃のタイミング | 入力→即実行 | 入力→保存→後で取り出して実行 |
| 最初のリクエスト | 不正クエリが実行される | 不正クエリは実行されない(保存のみ) |
| WAF・入力検証の効果 | 有効(入力段階でブロック可能) | 限定的(保存は通過してしまう) |
| 発見の難しさ | 比較的発見しやすい | 時間差があり発見しにくい |
通常のSQLインジェクションの基礎については、SQLインジェクションとは?仕組み・攻撃例・対策の解説記事もあわせてご確認ください。
攻撃の仕組み(敵を知る)
二次SQLインジェクションが成立する流れを「想定例」として示します。以下はあくまで概念説明であり、実在の企業・システムを指すものではありません。
1. 攻撃者の入力(第一段階:保存)
攻撃者がアカウント登録フォームで次のようなユーザー名を入力します。
# 攻撃者が登録するユーザー名(想定例) admin'--
アプリケーションが入力値をエスケープして保存するため、データベースには admin'-- という文字列がそのまま格納されます。この時点では不正なクエリは実行されていません。
2. 別機能でのクエリ組み立て(第二段階:発動)
後日、パスワード変更機能が呼ばれたとき、アプリケーションはログイン中のユーザー名をデータベースから取り出し、そのままクエリに組み込みます。
# 安全でないクエリ組み立て(想定例・概念的表現) # DBから取り出した username = "admin'--" をそのまま埋め込むと… UPDATE users SET password = '新パスワード' WHERE username = 'admin'--' # -- 以降はSQLコメントとして無視される # 実際に実行されるのは: UPDATE users SET password = '新パスワード' WHERE username = 'admin' # → 攻撃者は adminアカウントのパスワードを書き換えてしまう
結果として、攻撃者は「自分のパスワードを変更した」つもりでも、実際には管理者アカウントのパスワードを書き換えてしまいます。保存時のエスケープが、取り出し時にはそのままSQL構文として解釈されてしまうのが根本原因です。
最初のリクエスト(登録)では何もエラーが起きないため、攻撃者がいつ仕込んだかも把握しにくいのが二次インジェクションの怖いところです。
具体的な防御手順
1. 保存時も取り出し時もプレースホルダを徹底する
二次SQLインジェクションの根本原因は「DBから取り出したデータは安全なはず」という誤った前提でクエリを組み立てることです。データの出所がDBであっても、ユーザー入力と同等の危険なデータとして扱うことが鉄則です。
すべてのSQLクエリでプレースホルダ(バインド変数)を使用してください。
# NGパターン(文字列連結によるクエリ生成・想定例) sql = "UPDATE users SET password = '" + new_password + "' WHERE username = '" + username + "'" # OKパターン(プレースホルダ使用・想定例) sql = "UPDATE users SET password = ? WHERE username = ?" cursor.execute(sql, [new_password, username])
プレースホルダを使えば、DBに admin'-- が格納されていても、クエリ組み立て時に安全な文字列として処理され、SQL構文として解釈されません。
2. 「一度サニタイズ済み」を信頼しない設計にする
「データベースに入っている値は入力時にサニタイズ済みだから信頼できる」という設計思想がそもそも危険です。
・データの取得元を問わずプレースホルダを使う(DBから読んだ値も、APIから受け取った値も同様)
・内部APIやバッチ処理にも同じルールを適用する(フロントエンドとは別の処理経路でも安全に扱う)
・コードレビューで「DBから取り出した値を直接クエリに埋め込む箇所」を重点的に確認する
マイクロサービス構成やバッチ処理では「このデータはフロントから来ていないから安全」という思い込みが生じやすいため、特に注意が必要です。
3. ORMを正しく使い、生SQLを極力書かない
Django ORM・ActiveRecord・Hibernate等のORMは、標準的な操作でプレースホルダが自動適用されます。ただし、ORMにも生のSQL文字列を受け付けるメソッドが存在するため、それを誤用すると保護が無効になります。
# NGパターン(ORMのrawメソッドに文字列結合で渡す・想定例・概念) # DB.raw("SELECT * FROM users WHERE name = '" + username + "'") # OKパターン①(ORMのメソッドチェーンで自動バインド) # User.where(name: username) # OKパターン②(rawを使う場合はパラメータとして渡す) # DB.raw("SELECT * FROM users WHERE name = ?", [username])
パフォーマンスや複雑なクエリのために生SQLを書く場面は必ずあります。そのような箇所こそ、コードレビューでプレースホルダが正しく使われているかを確認する優先ポイントです。
中小企業でも今日からできること
大きなコスト投資なく着手できる対策を3点挙げます。
・コード棚卸し: grepや静的解析ツールで「DBから取り出した値を直接クエリに連結している箇所」を洗い出し、プレースホルダへの置き換えを優先対応する
・ORM方針統一: 新規開発は生SQLを極力書かないアーキテクチャを原則とし、ORMのrawメソッドを使う際のレビュールールを明文化する
・WAFの補完的位置づけを認識する: WAFは保存時の入力は検査できても、取り出し時のクエリ実行は検知できない。コード側の修正が本質的な対策であると認識する
WAFの役割と限界についてはWAFとは?の解説記事もご参照ください。
よくある誤解と注意点
「エスケープしてDBに保存すれば安全」は誤り
エスケープはデータを安全に保存するための処理であり、「クエリに組み込んでも安全になる」という意味ではありません。DBから取り出した値を新たなクエリに埋め込む際は、必ずプレースホルダを使ってください。
「二重エスケープ」という誤った対策に注意
「保存時のエスケープだけでは不安だから取り出し時にも再エスケープする」という対応を見ることがあります。しかし二重エスケープはデータが意図しない形に変形し、表示の文字化けや別の不具合につながります。正しい対策はプレースホルダの徹底であり、二重エスケープではありません。
Blind型との組み合わせは検知が特に難しい
時間ベース・エラーベースで情報を引き出すBlind SQLインジェクションの手法と組み合わさると、攻撃の痕跡がさらに残りにくくなります。定期的な静的コード解析(SAST)ツールの活用も検討してください。

本記事のまとめ
| ポイント | 内容 |
|---|---|
| 二次SQLインジェクションとは | 悪意あるデータをDBに保存し、後のクエリ組み立て時に攻撃が発動するインジェクション |
| 通常との違い | 保存時には正常に見え、取り出し・再利用時に脆弱性が現れる時間差攻撃 |
| 根本対策 | データの出所を問わず、すべてのクエリでプレースホルダを使う |
| 誤った対策 | 「保存済みだから安全」「二重エスケープで対応」は通用しない |
| コード確認ポイント | DBから取り出した値を直接クエリに連結している箇所を重点確認 |
セキュアコーディングの全体像については、セキュアコーディングとは?安全なWebアプリを作るための基本原則と実装ガイドもあわせてご一読ください。
PR
体系的に学ぶ 安全なWebアプリケーションの作り方 第2版(徳丸浩)
SQLインジェクション・XSS・CSRFなどWebアプリの脆弱性を体系的に解説した定番書。二次SQLインジェクションを含む実装レベルの防御知識を深めるのに最適な一冊です。
