
SQLインジェクション診断
SQLインジェクションはデータベースを直接攻撃する最も危険な脆弱性の一つです。 認証バイパス、データ窃取、データ改ざん、さらにはサーバー全体の乗っ取りに至る可能性があります。
チェック項目
4種類のSQLインジェクションを検出
Classic SQLi(インバンド)
危険度: 非常に高攻撃者がSQLクエリに直接ペイロードを注入し、レスポンスに結果が表示される最も基本的なSQLインジェクション。入力フォームやURLパラメータを通じて実行されます。
攻撃コード例
// 脆弱なコード(Node.js + MySQL)
const query = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "'";
// 攻撃入力
// username: admin' --
// password: (任意)
// 生成されるSQL: SELECT * FROM users WHERE username = 'admin' --' AND password = ''
// "--" 以降がコメントアウトされ、パスワードチェックがバイパスされるBlind SQLi(ブラインド)
危険度: 高クエリの結果が直接レスポンスに表示されないが、条件分岐(True/False)やレスポンス時間の差異から情報を一文字ずつ抽出する攻撃。Boolean-basedとTime-basedの2種類があります。
攻撃コード例
// Boolean-based Blind SQLi
// URL: /user?id=1 AND 1=1 → 正常レスポンス
// URL: /user?id=1 AND 1=2 → エラーまたは空レスポンス
// Time-based Blind SQLi
// URL: /user?id=1; WAITFOR DELAY '0:0:5'--
// レスポンスに5秒の遅延 → SQLiが存在する証拠
// データベース名の1文字目を抽出
// /user?id=1 AND SUBSTRING(database(),1,1)='a' → True/Falseで判定エラーベースSQLi
危険度: 高データベースが返すエラーメッセージにSQL文やデータベース構造に関する情報が含まれている場合に悪用される攻撃。エラーメッセージからテーブル名、カラム名、データベースバージョンなどを特定できます。
攻撃コード例
// エラーメッセージの例(本番環境で表示すべきでない)
// "You have an error in your SQL syntax near '1'' at line 1"
// "ERROR: column "password" does not exist" (PostgreSQL)
// "Microsoft OLE DB Provider for SQL Server error '80040e14'"
// 攻撃ペイロード
// /product?id=1' AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT version())))--UNIONベースSQLi
危険度: 非常に高UNION SELECT文を使って、元のクエリの結果に任意のテーブルからデータを追加する攻撃。データベース内の全てのテーブル、カラム、データを抽出できる可能性があります。
攻撃コード例
// 攻撃ペイロード
// /product?id=1 UNION SELECT username, password, NULL FROM users--
// カラム数の特定
// /product?id=1 ORDER BY 1-- → 正常
// /product?id=1 ORDER BY 2-- → 正常
// /product?id=1 ORDER BY 3-- → エラー → カラム数は2
// テーブル名の列挙(MySQL)
// /product?id=-1 UNION SELECT table_name, NULL FROM information_schema.tables--脆弱性の背景
なぜSQLインジェクション対策が重要なのか
SQLインジェクションは、OWASP Top 10で常に上位にランクされる脆弱性であり、 成功した場合の被害は甚大です。データベースはWebアプリケーションの中核であり、 ここが侵害されるとアプリケーション全体が危険にさらされます。
データの完全な漏洩
全ユーザーの個人情報、パスワードハッシュ、クレジットカード情報など、データベースに格納された全データが抽出される可能性があります。
認証のバイパス
ログインフォームにSQLペイロードを注入することで、パスワードを知らずに管理者としてログインできます。WHERE句の条件を常にTrueにする手法が典型的です。
データの改ざん・削除
UPDATE文やDELETE文、さらにはDROP TABLE文を実行され、データの改ざんや完全な削除が行われる可能性があります。
サーバーの乗っ取り
データベースの権限によっては、OSコマンドの実行やファイルシステムへのアクセスが可能になり、サーバー全体が乗っ取られるリスクがあります。
実際の被害事例
SQLインジェクションによる攻撃事例
Sony Pictures SQLインジェクション攻撃(2011年)
LulzSecハッカーグループがSony Picturesのウェブサイトに対してSQLインジェクション攻撃を実行。100万件以上のユーザーアカウント情報(メールアドレス、パスワード)が流出しました。パスワードが平文で保存されていたことも問題視されました。
Heartland Payment Systems データ漏洩(2008年)
SQLインジェクションを起点とした攻撃で、決済処理会社Heartlandから1億3,000万件以上のクレジットカード情報が漏洩。当時史上最大規模のデータ漏洩事件となりました。被害総額は1億4,000万ドル以上。
TalkTalk ハッキング事件(2015年)
英国の通信会社TalkTalkがSQLインジェクション攻撃を受け、15万7,000件の顧客データが漏洩。攻撃者は15歳と17歳の少年で、基本的なSQLi対策で防げる攻撃でした。GDPRの前身であるData Protection Actに基づき、40万ポンドの罰金が科されました。
検出メカニズム
Security Scannerの検出方法
パラメータの特定
URLパラメータ、フォームフィールド、Cookieなど、SQL文に影響を与える可能性のある入力ポイントを特定します。
SQLiペイロードの注入
シングルクォート(')、UNION SELECT、OR 1=1、WAITFORなどのテストペイロードを各パラメータに注入します。
エラーレスポンスの解析
SQL構文エラーメッセージ、データベース固有のエラーパターン(MySQL、PostgreSQL、SQL Server)を検出します。
挙動の差異検出
True条件(AND 1=1)とFalse条件(AND 1=2)でレスポンスに差異があるかを比較し、Blind SQLiの可能性を判定します。
リスクレベルの判定
SQLiの種類、データベースの種類、影響範囲に基づいて包括的なリスクレベルを判定します。
修正方法
SQLインジェクションの防御方法
1. パラメータ化クエリ(Prepared Statements)
SQLインジェクション対策の最も効果的な方法です。SQL文とデータを分離することで、注入を構造的に不可能にします。
// 脆弱なコード(文字列結合)
const query = "SELECT * FROM users WHERE id = " + userId; // NG
// 安全なコード(パラメータ化クエリ)
// Node.js + mysql2
const [rows] = await connection.execute(
'SELECT * FROM users WHERE id = ?',
[userId]
);
// Node.js + pg (PostgreSQL)
const result = await pool.query(
'SELECT * FROM users WHERE id = $1',
[userId]
);
// Supabase
const { data } = await supabase
.from('users')
.select('*')
.eq('id', userId);2. ORM(Object-Relational Mapping)の使用
ORMを使用することで、SQL文を直接記述する機会を減らし、パラメータ化クエリが自動的に適用されます。
// Prisma ORM(TypeScript)
const user = await prisma.user.findUnique({
where: { id: userId }, // 自動的にパラメータ化
});
// Drizzle ORM
const users = await db.select()
.from(usersTable)
.where(eq(usersTable.id, userId));
// 注意: ORMでも生SQL(raw query)を使う場合は注意
// Prisma の $queryRaw はテンプレートリテラルでパラメータ化
const result = await prisma.$queryRaw`
SELECT * FROM users WHERE id = ${userId}
`;3. 追加の防御層
最小権限の原則
アプリケーション用のデータベースユーザーには必要最小限の権限のみ付与。DROP、ALTER、FILE権限は絶対に付与しない。
エラーメッセージの抑制
本番環境ではデータベースのエラーメッセージをユーザーに表示しない。汎用的なエラーメッセージを表示し、詳細はサーバーログに記録。
WAF(Web Application Firewall)
SQLiパターンをリアルタイムで検出・ブロックするWAFを導入。ただし、WAFはあくまで補助的な防御であり、根本的な対策(パラメータ化クエリ)の代替にはならない。
入力バリデーション
数値パラメータにはNumber型への変換、文字列には長さ制限と文字種制限を適用。ホワイトリスト方式が推奨。
SQLインジェクションを今すぐ診断
あなたのWebアプリにSQLインジェクションの脆弱性がないか自動テスト。 データベースを守る最初のステップを今すぐ始めましょう。