Web セキュリティ

SQL インジェクション

約 4 分で読めます

SQL インジェクションとは

SQL インジェクションとは、Web アプリケーションのデータベースクエリにユーザー入力が適切に処理されずに組み込まれることで、攻撃者が任意の SQL 文を実行できてしまう脆弱性です。データベース内の全データの窃取、改ざん、削除、さらにはサーバーの OS コマンド実行にまで被害が及ぶ可能性があります。OWASP Top 10 では SQL インジェクション (CWE-89) は Injection カテゴリに分類され、2017 年版では A1:2017-Injection として首位、2021 年版では A03:2021、2025 年版では A05:2025 に位置づけられています。

Web 経由の SQL 注入を公に扱った初期の文献としては、1998 年 12 月の Phrack Magazine 第 54 号に掲載された記事「NT Web Technology Vulnerabilities」が知られています。同記事は、Web ページの入力値をそのまま連結した SQL 文に別の SQL 文を継ぎ足せることを、MS SQL Server 6.5 が複数文のバッチ実行を許す点を例に指摘していました。この指摘から四半世紀以上を経た 2026 年 8 月時点でも、根本的な対策が明確であるにもかかわらず、実装の不備により脆弱性が残存するケースが後を絶ちません。

攻撃の原理と種類

SQL インジェクションは、アプリケーションが SQL クエリを文字列連結で組み立てる際に発生します。例えば、ログインフォームで入力されたユーザー名を SELECT * FROM users WHERE name = '入力値' のようにクエリに直接埋め込む場合、攻撃者が入力値に ' OR '1'='1 と入力すると、WHERE 句が常に真となり、認証をバイパスできます。

主な攻撃の種類

  • UNION ベース: UNION SELECT を注入して、本来アクセスできないテーブルのデータを取得する。カラム数と型を合わせる必要があるが、エラーメッセージやレスポンスの変化から推測可能
  • エラーベース: 意図的にエラーを発生させ、エラーメッセージに含まれるデータベースの情報 (テーブル名、カラム名、データ) を読み取る
  • ブラインド SQL インジェクション: エラーメッセージが表示されない場合に、真偽値の条件分岐 (Boolean-based) やレスポンス時間の差 (Time-based) を利用して、1 ビットずつ情報を抽出する
  • 帯域外 (Out-of-Band): DNS リクエストや HTTP リクエストを通じて、データベースから外部サーバーにデータを送信させる

自動化ツール (sqlmap など) の存在により、高度な技術知識がなくても SQL インジェクションの検出と悪用が可能になっています。

被害の実態と影響範囲

SQL インジェクションによる被害は、データの窃取にとどまりません。

  • データの窃取: ユーザーの個人情報、認証情報、クレジットカード番号など、データベースに格納されたすべてのデータが漏洩する可能性がある
  • データの改ざん・削除: UPDATE や DELETE 文を注入し、データを改ざんまたは削除する。DROP TABLE でテーブル全体を削除することも可能
  • 認証のバイパス: ログインクエリを操作して、パスワードを知らずに任意のアカウント (管理者を含む) としてログインする
  • サーバーの制御奪取: データベースの機能 (MySQL の LOAD_FILE、SQL Server の xp_cmdshell など) を悪用して、OS レベルのコマンドを実行する

OWASP の 2025 年版 Top 10 の集計では、SQL インジェクション (CWE-89) は報告頻度そのものは Cross-Site Scripting より低い一方、影響度の大きい脆弱性として 1 万 4 千件を超える CVE が挙げられています。WAF による検知は有効な補助策ですが、巧妙なエンコーディングやコメント挿入で WAF をバイパスする手法も知られており、根本対策の代替にはなりません。

根本的な対策

SQL インジェクションの根本対策は明確です。SQL 文の構造とデータを分離する実装を徹底すれば、攻撃経路の大半は塞げます。ただし OWASP が注記しているとおり、呼び出し側でパラメータ化していても、ストアドプロシージャの内部で PL/SQL や T-SQL が文字列連結や EXECUTE IMMEDIATE による実行を行っていれば脆弱性は残ります。

プリペアドステートメント (パラメータ化クエリ)

SQL 文の構造とデータを分離し、ユーザー入力が SQL の構文として解釈されることを防ぎます。OWASP Top 10 の Injection 項目でも、インタープリタを介さない安全な API とパラメータ化されたインターフェイスの利用が第一の選択肢として挙げられています。主要なデータベースアクセスライブラリはプリペアドステートメントに相当する仕組みを備えているため、文字列連結でクエリを組み立てている箇所を置き換えるのが出発点になります。なお、テーブル名や列名といった SQL の構造部分はプレースホルダーに置けず、エスケープでも保護できません。並び替え対象の列名などをユーザー入力で決める場合は、許可リストで受け付ける値を固定します。動的な組み立てが避けられない箇所のエスケープは、パラメータ化できない残りを塞ぐ補助手段と位置づけます。

ORM の活用

ORM (Object-Relational Mapping) を使用すると、SQL を直接記述する機会が減り、SQL インジェクションのリスクが低下します。ただし、ORM の生クエリ機能やカスタムクエリを使用する場合は、プリペアドステートメントと同様の注意が必要です。

多層防御

  • 最小権限の原則: アプリケーションが使用するデータベースアカウントの権限を必要最小限にする。読み取り専用の操作には読み取り専用アカウントを使用する
  • 入力のバリデーション: 数値フィールドには数値のみ、メールアドレスフィールドには適切な形式のみを受け付ける。ただし、これは補助的な対策であり、プリペアドステートメントの代替にはならない
  • エラーメッセージの制御: データベースのエラーメッセージをユーザーに直接表示しない。エラーベースの SQL インジェクションによる情報漏洩を防ぐ
  • 脆弱性管理: 定期的なセキュリティスキャンとコードレビューで、SQL インジェクションの脆弱性を早期に発見する
  • セキュリティヘッダーとの役割分担: セキュリティヘッダーはブラウザ側の挙動を制御する仕組みで、サーバー側でクエリが組み立てられる SQL インジェクションには効かない。同じ入力欄に潜む別のリスク (XSS など) を受け持つ層として使い分ける

よくある誤解

入力値をエスケープすれば SQL インジェクションは防げる
エスケープ処理は実装ミスが起きやすく、文字エンコーディングの違いや特殊なケースで漏れが生じる。プリペアドステートメントは SQL の構造とデータを根本的に分離するため、エスケープ漏れのリスクがない。エスケープではなくプリペアドステートメントを使うべき。
NoSQL データベースなら SQL インジェクションは発生しない
SQL インジェクションは発生しないが、NoSQL インジェクションという同種の脆弱性が存在する。MongoDB では JSON クエリにユーザー入力を直接埋め込むと、クエリ演算子の注入が可能になる。データベースの種類に関係なく、ユーザー入力の適切な処理は必須。

SQL インジェクションと XSS の比較

SQL インジェクション

サーバー側のデータベースを標的にする。データの窃取・改ざん・削除が可能。プリペアドステートメントで根本的に防御できる。被害はサーバー側のデータに及ぶ。

XSS

クライアント側のブラウザを標的にする。Cookie 窃取やセッションハイジャックが主な被害。出力エスケープと CSP で防御する。被害はユーザーのブラウザ上で発生する。

共有する

関連用語

関連記事