モジュール一覧
診断モジュール 04

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の検出方法

01

パラメータの特定

URLパラメータ、フォームフィールド、Cookieなど、SQL文に影響を与える可能性のある入力ポイントを特定します。

02

SQLiペイロードの注入

シングルクォート(')、UNION SELECT、OR 1=1、WAITFORなどのテストペイロードを各パラメータに注入します。

03

エラーレスポンスの解析

SQL構文エラーメッセージ、データベース固有のエラーパターン(MySQL、PostgreSQL、SQL Server)を検出します。

04

挙動の差異検出

True条件(AND 1=1)とFalse条件(AND 1=2)でレスポンスに差異があるかを比較し、Blind SQLiの可能性を判定します。

05

リスクレベルの判定

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インジェクションの脆弱性がないか自動テスト。 データベースを守る最初のステップを今すぐ始めましょう。