はじめに
Webエンジニア、インフラ担当、セキュリティ研究者の間で “よく聞くのに意外と理解されていない” ヘッダーのひとつが X-Forwarded-For(XFF)。
結論:XFF は「元のクライアントIPアドレス」を伝えるための HTTP ヘッダー。
リバースプロキシやロードバランサを通過した際に追加される。
しかし、同時に 攻撃者が悪用しやすい脆弱ポイント にもなる。
この記事では、XFF の基本から、攻撃シナリオ、守るためのベストプラクティスまで一気に解説する。
1. X-Forwarded-Forとは?
HTTPヘッダー X-Forwarded-For は、以下のように アクセス元のクライアントIPを残す ために使われる。
X-Forwarded-For: 203.0.113.52
プロキシを何段も通る場合、左から順番に追加されていく:
X-Forwarded-For: 203.0.113.52, 10.0.0.8, 10.0.0.9
- 一番左:元のクライアント
- 右側:経由したプロキシ
2. なぜ必要なのか?
Webアプリの前に以下のような構成が置かれている場合:
Client → CDN → Reverse Proxy → App Server
アプリサーバが見えるのは「直前のプロキシのIP」。
これだと:
- ログが正しく残らない
- レートリミットが効かない
- GeoIP 判定が狂う
そこで XFF を使って “本当のクライアントIP” を渡す。
3. しかし──攻撃者も簡単に偽装できる
実は、XFF は ユーザが好きな値を入れられる HTTP ヘッダー。
攻撃者のリクエスト例:
X-Forwarded-For: 127.0.0.1
アプリが XFF を信用していると……
- 「ローカルからのアクセス」と誤解
- 内部専用の管理画面が開く
- レートリミットが無効化される
などの致命的な脆弱性につながる。
4. 実際の攻撃シナリオ
シナリオ1:内部 IP 信頼バイパス
多くの Web アプリは内部IPを特別扱いする:
if client_ip == "127.0.0.1":
allow_admin()
攻撃者:
X-Forwarded-For: 127.0.0.1
→ 管理画面に堂々と侵入。
現実に多数の CVE が存在する典型的脆弱性。
シナリオ2:レートリミット bypass
IP で rate-limit する実装:
limit_per_minute per_ip=60
攻撃者は毎回ヘッダーを変えるだけ:
X-Forwarded-For: 1.1.1.1
X-Forwarded-For: 1.1.1.2
X-Forwarded-For: 1.1.1.3
→ 無限リクエスト、爆撃し放題。
シナリオ3:SSRF 制限 bypass
内部アクセス禁止:
deny 127.0.0.0/8
でも判断が XFF ベースだと:
X-Forwarded-For: 127.0.0.2
→ SSRF 保護を突破。
シナリオ4:WAF / CDN 誤判定の利用
Cloudflare などの前に Webサーバが直接 XFF を信用すると:
X-Forwarded-For: 203.0.113.254
→ WAF が「ユーザIPはこれか」と誤解して
ログが汚れ、アクセス制御も崩壊。
5. NGINX / Apache / Cloudflare での正しい扱い
ポイント:信頼できるプロキシだけを信用する
“誰でも送れる XFF を無条件に信じてはダメ!”
NGINX の安全設定
set_real_ip_from 10.0.0.0/8;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
-
set_real_ip_from→ 信頼するプロキシだけ(CDN、LBなど) - それ以外の XFF は無視される
Apache の例
RemoteIPHeader X-Forwarded-For
RemoteIPTrustedProxy 10.0.0.0/8
Cloudflare + NGINX の組み合わせ
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
...
real_ip_header CF-Connecting-IP;
Cloudflare では通常 XFF より CF-Connecting-IP を使う。
6. アプリケーション側のベストプラクティス
- 一番左の XFF を信用しない
- 信頼できるプロキシから来たヘッダーのみ採用
- XFF が複数あるときは「最初の不正なIP」を検証
- クライアントIPに依存した認証・権限判断をしない
(管理画面を “IPだけで” 認証するのは危険)
7. XFF を使ったペンテスト Tips
ペンテスターは XFF をこう使う:
内部アクセス偽装
X-Forwarded-For: 127.0.0.1
レートリミット bypass
X-Forwarded-For: $(random_ip)
BurpSuite で自動化
Burp Intruder → “Add Header” → XFF
wfuzz
wfuzz -H "X-Forwarded-For: FUZZ" -u http://target/ --hw 0 -w ips.txt
まとめ
| テーマ | 要点 |
|---|---|
| XFF とは? | 元のクライアントIPを伝えるためのヘッダー |
| 役割 | ログ、レート制御、GeoIP判定、CDN/プロキシ連携 |
| 危険性 | 攻撃者が簡単に偽造可能 |
| 典型攻撃 | 管理画面バイパス、レートリミット bypass、SSRF bypass |
| 対策 | 信頼できるプロキシだけを許可し、無条件に信じない |
| 実装方法 | NGINX/Apacheの real_ip 系設定を正しく行う |
X-Forwarded-For 偽装攻撃 — シーケンス図
攻撃者が
X-Forwarded-For: 127.0.0.1
を付与して、アプリが「内部IPからのアクセス」と誤認して管理画面に入る流れ。
XFF 多段偽装攻撃(プロキシ付き)
攻撃者はプロキシを使い、本来なら:
192.0.2.55(攻撃者のIP)
10.0.0.8(プロキシ)
10.0.0.9(LB)
などが並ぶはず。
しかし 一番左に攻撃者が追加した 127.0.0.1 を置くことで bypass。
レートリミット bypass(XFFローテーション)
攻撃者は XFF を毎回変えて rate-limit を無力化する。
SSRF ガード bypass(XFF ベース判定)
XFF を信用してしまっているアプリが
「内部IPからのアクセスは禁止」 を誤った条件で行っている場合。