1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【セキュリティ】HTTP Header Injection による SQL Injection 完全解説

Posted at

まとめに

― User-Agent を侵入口にした “ログ経由 SQLi” の仕組みと攻撃手法 ―

現代の Web アプリでは、User-Agent や Referer といった HTTP ヘッダーを「ただのログ情報」として扱いがちです。
しかし、これらはすべて ユーザーが自由に書き換え可能な“入力値”

そして入力値が SQL にそのまま埋め込まれた瞬間──
SQL Injection の大門が開きます
(門番は爆睡しています。攻撃者はすっと通り抜けます。)

この記事では、User-Agent を利用した HTTP Header Injection → SQL Injection の流れを、実際の脆弱コードと攻撃パターンを交えて徹底的に解説していきます。


1. シナリオ概要:User-Agent が DB に保存されるアプリ

対象アプリは次のような挙動を持っています。

/httpagent/ にアクセスすると

  1. サーバがリクエストの User-Agent を取得
  2. その値を logs テーブルに INSERT
  3. あとで同じ値で SELECT して表示

User-Agent の流れ:

HTTP Request → User-Agent → INSERT INTO logs → SELECT FROM logs → Webに表示

ログを残すだけの“ harmless 処理 ”に見えて、
ここに SQL Injection の地雷が全力で埋まっています。


2. 問題のサーバーコード(脆弱版)

PHP(mysqli)で書かれたコードはこんな感じ:

$userAgent = $_SERVER['HTTP_USER_AGENT'];

$insert_sql = "INSERT INTO logs (user_Agent) VALUES ('$userAgent')";
$conn->query($insert_sql);

$sql = "SELECT * FROM logs WHERE user_Agent = '$userAgent'";
$result = $conn->query($sql);

はい、犯人はココです。

  • ユーザー入力
  • エスケープなし
  • SQLに直埋め込み

という 3 連コンボ。

User-Agent は curl や Burp Suite なら自由に書き換えられるため、
攻撃者は SQL 文を丸ごと乗っ取る ことができます。


3. User-Agent を悪用した攻撃の流れ

3.1 Step1:まずは SQL が壊せることを確認(構文エラー)

User-Agent: test'--

これが SQL になると:

INSERT INTO logs (user_Agent) VALUES ('test'--');

-- 以降はコメント化されるため、
構文が崩れ、DB がエラーを返します。

この瞬間、

ヘッダーを経由して SQL が“壊せる”ことが確定

つまり SQL Injection 攻撃が実行可能であるという合図です。


3.2 Step2:ログ閲覧時の SELECT を乗っ取る

次のような User-Agent を送る:

User-Agent: ' OR 1=1--

すると SELECT はこうなる:

SELECT * FROM logs WHERE user_Agent = '' OR 1=1--';

OR 1=1 により条件が常に TRUE になるため、
logs テーブルの全レコードが表示される

小手調べの OR 1=1 攻撃がここで成立します。


3.3 Step3:UNION を使って別テーブルのデータを盗む

本命の攻撃はこちら:

User-Agent: ' UNION SELECT username, password FROM user; --

SQL はこうなる:

SELECT * FROM logs WHERE user_Agent = ''
UNION
SELECT username, password FROM user;
-- ';

テーブル構造が一致していれば…

  • logs の内容
  • user テーブルの username / password

これらが 1 つのレスポンスに並んで返ってきます。

つまり攻撃者のブラウザに ユーザー名リスト & パスワード(ハッシュ) が露出。

ログ表示ページが、データ漏洩の出入口になってしまう わけです。


4. なぜ「HTTP Header Injection」になるのか?

フォーム入力だけが危険、という時代は終わりました。
攻撃者が自由に変更できるものは、すべて 入力値 です。

  • User-Agent
  • Referer
  • X-Forwarded-For(IP偽装用、危険度MAX)
  • Cookie
  • Host ヘッダー

これらを信じて SQL に流すと、
すべて SQL Injection の踏み台になる

User-Agent を通じた
ハイブリッド型の Second-Order SQL Injection に近い挙動になります。


5. 防御:パラメータ化クエリ以外は信じるな

NG:自前エスケープ

$ua = $conn->real_escape_string($_SERVER['HTTP_USER_AGENT']);

→ 漏れたら即死。
→ エスケープ対象外の DB(MySQL→PostgreSQL)で死ぬ。
→ UNION, コメント, エスケープ外手法に弱い。

最強の防御:Prepared Statement(プリペアドステートメント)

// INSERT
$stmt = $conn->prepare("INSERT INTO logs (user_Agent) VALUES (?)");
$stmt->bind_param("s", $userAgent);
$stmt->execute();

// SELECT
$stmt = $conn->prepare("SELECT * FROM logs WHERE user_Agent = ?");
$stmt->bind_param("s", $userAgent);
$stmt->execute();

これで User-Agent に ' UNION SELECT … を入れても、
SQL 文には決して変形しません。

値として扱われるので、SQL が壊れない。
これが唯一確実な防御です。


6. ログだから安全? → 安全ではありません

「ログに入れるだけだから無害」と考えるのは危険です。

  • ログの閲覧画面で SQL に再投入される
  • ログを CSV に落として別処理でパースされる
  • ログの全文検索で SQL を使っている
  • 管理画面でフィルタ条件に利用している

ログに入った瞬間は harmless に見えても、
二次利用したときに爆発するのが Second-Order SQL Injection

つまり「ログでも絶対にサニタイズ必要」。


まとめ:User-Agent の一文字がデータベースを破壊する

項目 内容
攻撃入口 User-Agent などの HTTP ヘッダー
原因 SQL に直接値を埋め込む(非パラメータ化)
主な攻撃 OR 1=1 / UNION SELECT / コメント注入
発生ポイント ログ記録処理、ログ閲覧処理
防御 Prepared Statement 一択

HTTP ヘッダーは“信頼できないユーザー入力”の代表格です。
ログに保存するだけ、と思っても、そのログが後で SQL に再利用されれば即アウト。

「ヘッダー=危険」と認識し、必ずパラメータ化クエリを使う。
これだけで、多くの攻撃を根絶できます。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?