SQLインジェクションとは?仕組み・攻撃例・対策をコード付きで解説
SQLインジェクションは、入力値をSQL文に文字列連結してしまうWebアプリケーションに対し、攻撃者が細工した文字列を送り込んでデータベースを不正操作する攻撃です。会員情報の窃取・改ざん、ログイン認証の回避まで引き起こす、Webアプリの脆弱性の中でも被害が重いものの代表格(CWE-89)です。この記事では、実際に何が起きるのかをコードで示し、IPA「安全なウェブサイトの作り方」に沿った根本対策とテスト方法まで、実装の手が動くレベルで解説します。
まとめ:この記事の結論
- 正体:入力値をSQL文に連結する実装の欠陥。細工した文字列でSQL文の構造そのものを書き換えられる。
- 根本対策はプレースホルダ(プリペアドステートメント)一択。IPAも「根本的解決」と位置づける。中でも静的プレースホルダ(DBエンジン側でバインド)が原理的に安全。
- エスケープ処理は補助。実装漏れ・文字コードの穴が残るため単独では不十分。
- WAFは多層防御の一枚であって根本対策の代わりにはならない。プレースホルダ化とセットで運用する。
- テストは手動ペイロード(
' OR '1'='1等)+sqlmap・OWASP ZAP・Burp Suiteなどの診断ツールで確認する。
SQLインジェクションの仕組み|何が起きているのか
原因は単純で、ユーザー入力をSQL文の文字列に直接埋め込んでいることです。次のような実装が典型的な脆弱コードです。
// 脆弱なコード:入力を文字列連結している
$id = $_GET['id'];
$sql = "SELECT * FROM users WHERE id = '$id'";
ここで id に ' OR '1'='1 という値を送ると、組み立てられるSQLはこう変わります。
SELECT * FROM users WHERE id = '' OR '1'='1'
条件 '1'='1' は常に真なので、WHERE句が実質的に無効化され全レコードが返ります。攻撃者が入力欄に文字列を入れただけで、SQL文の「意味」を書き換えられてしまう——これがSQLインジェクションの本質です。狙われるのは主に、データの窃取・改ざん・削除、そして次に示す認証回避です。
代表的な攻撃手法【実例で理解する】
認証回避(ログインのすり抜け)
ログイン処理でユーザー名に admin'-- を入力すると、以下のようにパスワード条件がコメントアウトされます(-- はSQLの行コメント。MySQLでは -- の直後に空白が必要)。
SELECT * FROM users WHERE name = 'admin'-- ' AND pass = 'xxxx'
パスワードを知らなくても、管理者アカウントでログインが成立してしまいます。
UNIONベース攻撃(別テーブルの抽出)
元のクエリ(例:SELECT id, name FROM users)に UNION SELECT を接ぎ木し、本来表示されない別テーブルの中身を画面に引き出す手口です。元のクエリと同じカラム数・型に合わせることで、クレジットカード番号やパスワードハッシュを一覧に混ぜて出力させます。
' UNION SELECT card_no, name FROM credit_cards --
ブラインドSQLインジェクション
エラーや結果が画面に出ない環境でも、「真のとき/偽のときで応答が変わる」ことを手がかりに1ビットずつ情報を復元できます。真偽で表示差を見るブール型と、SLEEP() などで応答時間の差を測る時間ベース型があり、ツールで自動化されるため「エラーを隠せば安全」は誤りです。
国内の被害事例
2005年5月、価格比較サイトへの不正アクセスによるサイト改ざん事件が発生し、手口はSQLインジェクションによるものとされました。その後もECサイトからのカード情報流出事案では、決済まわりのSQLインジェクションが原因に挙がるケースが続いています。10年以上前から知られる古典的な攻撃が今も被害を出し続けているのは、フレームワーク外の一部SQLで文字列連結が残りやすいためです。
SQLインジェクションとXSSの違い
混同されがちですが、攻撃対象と実行場所が異なります。SQLインジェクションはサーバー側のデータベースを狙い、XSS(クロスサイトスクリプティング)は他ユーザーのブラウザでスクリプトを実行させる攻撃です。
| 観点 | SQLインジェクション | XSS |
|---|---|---|
| 標的 | サーバーのDB | 閲覧者のブラウザ |
| 実行言語 | SQL | JavaScript等 |
| 主な被害 | 情報窃取・改ざん・認証回避 | セッション奪取・なりすまし |
| 根本対策 | プレースホルダ | 出力時のHTMLエスケープ |
CSRFを含む他の代表的な攻撃との違いは、CSRF・XSSの違いを整理した解説で合わせて確認してください。
SQLインジェクション対策【コード付き】
プレースホルダ(プリペアドステートメント)が根本対策
IPA「安全なウェブサイトの作り方」が根本的解決として挙げるのがプレースホルダです。SQL文の雛形に「値を入れる場所」を記号で用意し、実際の値は後からバインド処理で機械的に割り当てます。値がSQL文の構造に影響しないため、原理的にインジェクションが成立しません。主要言語の書き方は次の通りです。
// PHP(PDO)
$stmt = $pdo->prepare('SELECT * FROM users WHERE id = ?');
$stmt->execute([$id]);
// Java(JDBC)
PreparedStatement ps = con.prepareStatement(
"SELECT * FROM users WHERE id = ?");
ps.setString(1, id);
# Python(psycopg2・PyMySQL:%s。sqlite3は ? を使う)
cur.execute("SELECT * FROM users WHERE id = %s", (id,))
重要なのは静的プレースホルダと動的プレースホルダの違いです。静的はDBエンジン側でバインドするため原理的に安全(ISO/JISでいうPrepared Statement)ですが、動的はライブラリ側でエスケープして埋め込むため実装依存の穴が残り得ます。PHP/PDOでは、次の設定でエミュレーションを切り、静的プレースホルダを使わせるのが安全側です。
$pdo = new PDO($dsn, $user, $pass, [
PDO::ATTR_EMULATE_PREPARES => false,
]);
エスケープ処理の限界と使いどころ
特殊文字(' など)を無害化するエスケープは、プレースホルダを使えない一部の動的なテーブル名・カラム名指定などで補助的に使うものです。実装漏れが起きやすく、文字コードの取り扱いを誤ると回避されるため、主対策として単独では使いません。使う場合はDB接続の文字コードを明示し、その言語の標準エスケープ関数(自作しない)を用います。
入力値検証・最小権限・エラー抑制
プレースホルダを土台に、次を重ねて被害を抑えます。入力値検証(数値項目は数値型に限定するなど想定型・範囲を確認)、DBアカウントの最小権限化(アプリ用ユーザーに不要なDROP・テーブル横断権限を与えない)、詳細なエラーメッセージを画面に出さない(SQLエラーは攻撃者の偵察材料になるため本番では抑制しログに残す)。これらは根本対策の代わりではなく、突破された場合の被害範囲を狭める多層防御です。
WAFによる多層防御とその限界
WAF(Web Application Firewall)は通信を検査し、SQLインジェクションらしいパターンを検知・遮断します。ソースを直せない既存システムの一時的な保護や、未知の攻撃への時間稼ぎとして有効です。ただしWAFは根本対策の代わりにはなりません。パターンをずらす回避(難読化・分割)で通過され得るうえ、正規の入力を誤遮断することもあるためです。位置づけはあくまで多層防御の一枚で、プレースホルダ化を本丸に据えたうえで併用するのが正解です。仕組みはWAFとは何かを解説した記事で確認できます。
SQLインジェクションのテスト・診断方法
手動での確認(テスト用ペイロード)
自社サイトの検証では、入力欄やURLパラメータに次のような文字列を入れ、エラーや挙動の変化が出ないかを確認します。応答内容や時間が変わる場合は脆弱性の疑いがあります(自身が管理する環境でのみ実施)。
' OR '1'='1 ← 常に真の条件を注入
' ← 単一引用符でSQLエラーを誘発
'; WAITFOR DELAY '0:0:5'-- ← 応答遅延で時間ベースを確認
診断ツールで自動化する
網羅的に洗い出すには専用ツールを使います。sqlmapはSQLインジェクションに特化し、検出から悪用可否の確認まで自動化します。OWASP ZAPは無償の総合スキャナ、Burp Suiteはプロキシとして手動検証と自動スキャンを両立します。
sqlmap -u "https://example.com/item?id=1" --batch --dbs
各ツールの使い分けはBurp Suiteによる脆弱性診断の解説が参考になります。
定期診断と外部委託
ツールでの自己点検に加え、リリース時や年次で第三者による脆弱性診断を実施すると、設定・ロジック起因の見落としを補えます。診断範囲や費用感は脆弱性診断の費用と外注判断の解説にまとめています。自社での実施が難しい場合は脆弱性診断サービスに委託する選択肢もあります。
よくある質問
SQLインジェクション攻撃を防ぐ方法はどれか(情報処理試験)
正答は「SQL文の組み立てにバインド機構(プレースホルダ)を使用する」です。入力値の長さ制限やパスワード強化、ファイアウォール設置は根本対策になりません。試験でも実務でも、プレースホルダによるSQL構築が正解です。
「’ OR ‘1’=’1」は何をしているのですか
WHERE句に常に真となる条件を注入し、本来の絞り込み条件を無効化しています。結果として全レコードの取得や、認証チェックのすり抜けが起こります。
SQLインジェクションの目的は何ですか
個人情報・認証情報の窃取が中心ですが、データの改ざん・削除、Webサイトの改ざん、管理者権限の奪取、さらに侵入の足がかりにも使われます。
エスケープ処理だけで対策として十分ですか
不十分です。実装漏れや文字コードの穴で回避され得ます。プレースホルダ(できれば静的)を主対策とし、エスケープはそれが使えない箇所の補助に留めます。
SQLインジェクションを検知するには
WAFやIDS/IPSでの通信検知に加え、DBのクエリログやアプリのエラーログで異常な構文・大量エラーを監視します。ただし検知は事後対応であり、まずプレースホルダで発生自体を断つのが優先です。
関連記事
- WordPress wp2shell(CVE-2026-63030・CVE-2026-60137)とは?未認証RCEの技術と今すぐ採るべき対応を解説:WordPressコアで実際に悪用されたSQLインジェクション連鎖の最新事例を、未認証RCEの視点で解説しています。
- CSRFとXSSの違いとは?特徴と攻撃手法
- WAFとは?Webアプリを守る仕組み
- Burp Suiteとは?Web脆弱性診断の基本
- 脆弱性診断の費用と外注判断
- 脆弱性診断サービス