リクエストを送ってXFF / X-Forwarded-For のヘッダー情報を確認する方法

こんにちはやまぱんです。

XFF / X-Forwarded-For まわりの検証で「そもそもどうやってヘッダーが付いているか確認するんだっけ?」と毎回手が止まるので、自分用にまとめておきます。Web サーバーを立ててログを見るのが王道ですが、もう少し手軽な方法もあります。

TL;DR

  • X-Forwarded-For(以降 XFF)は、プロキシや LB を経由したリクエストの 本来のクライアント IP を伝えるための事実上の標準ヘッダー 。標準化された後継として RFC 7239 の Forwarded ヘッダー がある。
  • 確認に使えるエンドポイントは複数ある。今回は httpbin.org を中心に、curl と PowerShell から XFF を付けて投げてレスポンスで確認する。
  • ただし XFF は クライアント側で自由に書ける ため、生のままアクセス制御や認証、レート制限に使うのは危険。手前の信頼できるプロキシ(Application Gateway / Front Door / CDN など)が 付け直してくれた値 を読むのが基本。

XFF / X-Forwarded-For とは

X-Forwarded-For は、プロキシや LB を経由したときに 元のクライアント IP を後段サーバーへ伝えるための HTTP ヘッダー です。複数段経由するとカンマ区切りで蓄積されていきます。

X-Forwarded-For: <client>, <proxy1>, <proxy2>

仕様自体は標準化されていない事実上の標準ですが、IETF では後継として Forwarded ヘッダー(RFC 7239)が定義されています。Forwardedfor=, by=, proto=, host= といった複数フィールドを 1 つのヘッダーにまとめられるのが特徴です。

参考:

XFF そのものの背景や詳しい説明は、別記事にも書いているのでそちらもどうぞ。

確認に使えるエンドポイントの選択肢

「XFF を付けてリクエストを投げたら、サーバー側でどう見えるか」を確認したいだけなら、サーバーを自前で立てなくても便利な公開サービスが使えます。

用途 エンドポイント 補足
受け取ったリクエスト内容を JSON で返してほしい httpbin.org /get?show_env=1 で proxy ヘッダー含めて返してくれる。Docker イメージあり
Webhook 風に 任意の URL を払い出してリクエスト履歴を GUI で見たい webhook.site URL を発行してそこに投げる。デバッグ用に便利
API テスト用にいろんなレスポンスを返してほしい postman-echo.com Postman 公式のエコーサービス
自前で完全に制御したい Azure Functions / Container Apps / Cloud Run など エンドポイントだけ作って Request.Headers をそのまま返す。社内検証で外に出せないときに便利

httpbin.org は手っ取り早いですが、外向き通信が制限される環境では使えないので、その場合は Docker でローカル起動 するか、上の代替に切り替えてください。

curl で XFF ヘッダーを付けて投げる

curl は -H オプションで任意のヘッダーを足せます。Linux でも macOS でも、Windows 10 以降に同梱されている curl.exe でも同じです。

XFF あり/なしの 2 本を比較すると分かりやすいです。

# XFF なし
curl https://httpbin.org/get?show_env=1

# XFF を付けて送る
curl -H "X-Forwarded-For: 117.117.117.117" https://httpbin.org/get?show_env=1

レスポンスの headers セクションに X-Forwarded-For が乗ってくるので、ちゃんと相手まで届いていることが確認できます。

参考:

PowerShell(Invoke-WebRequest / Invoke-RestMethod)で送る

Windows ネイティブで投げたいときは Invoke-WebRequestInvoke-RestMethod を使います。-Headers にハッシュテーブルを渡すと任意ヘッダーを追加できます。

# XFF なし(生のレスポンスが欲しい)
Invoke-WebRequest -Uri "https://httpbin.org/get?show_env=1"

# XFF を付ける
$headers = @{ "X-Forwarded-For" = "117.117.117.117" }
Invoke-WebRequest -Uri "https://httpbin.org/get?show_env=1" -Headers $headers

# JSON としてパースしたい場合は Invoke-RestMethod が楽
Invoke-RestMethod -Uri "https://httpbin.org/get?show_env=1" -Headers $headers |
    Select-Object -ExpandProperty headers

PowerShell の curlInvoke-WebRequest のエイリアスなので、curl.exe を明示的に呼びたいときは拡張子付きで curl.exe ... と書くのが安全です。

参考:

実行結果(Windows 11)

一部グローバル IP にモザイクをかけています。レスポンスに 117.117.117.117 が乗っているのが確認できます。FW や LB を経由してこの URL に届けば、同じ要領で XFF が見えるはず、というのが確認できる状態です。

XFF実行結果

実行結果(Ubuntu 22.04)

Windows と同じ結果になりました(スクショは割愛)。

以前は Windows の curl(= Invoke-WebRequest エイリアス)と Linux の curl で挙動が違うことが多かった印象ですが、今回は同じでした。明示的に挙動を揃えたいときは curl.exe を使うのが確実です。

自前のエコーサーバーで確認する

外部サービスに依存したくないときは、軽量なエコーサーバーをローカルで立てる方法もあります。今回は kongou-ae/light-ip-echo を使わせてもらいます。

準備

wget https://github.com/kongou-ae/light-ip-echo/releases/download/v0.0.7/light-ip-echo_linux_amd64 -O light-ip-echo
chmod 744 light-ip-echo

起動

80/tcp で待つので、ポート権限の都合で root で起動します。検証用の隔離環境で動かしてください。

sudo ./light-ip-echo

確認

単一の Ubuntu サーバー上で完結させたいので、ループバック宛にリクエストを投げて比較します。

# XFF なし
curl 127.0.0.1

# XFF を付ける
curl -H "X-Forwarded-For: 117.117.117.117" 127.0.0.1

レスポンスを見ると XFF の有無がはっきり分かります。

curl レスポンス比較

サーバー側でも標準出力にログが出るので、起動コンソール側でも確認できます。

サーバー側ログ

プロキシや CDN を経由するとどう書き換わるか

実際の経路で XFF がどう積まれるかは、手前のプロキシの実装次第です。Azure のフロントサービスの代表例を 2 つ紹介します。

  • Azure Application Gateway は受信した X-Forwarded-For の末尾にクライアントの IP:ポートを 追記 してバックエンドへ転送します。クライアントが付けてきた XFF はそのまま残るので、ログで見るときも「最後のエントリ」がゲートウェイから見たクライアント側 IP になります。
  • Azure Front DoorX-Forwarded-For(クライアント側 IP)、X-Forwarded-Host(元 Host)、X-Forwarded-Proto(元スキーム)などを付与してオリジンへ転送します。

CDN や WAF が クライアント由来の XFF を信用するかどうか は製品ごとに違うため、ログで「左端のエントリ」を見る前に必ずドキュメントを確認してください。

セキュリティ上の注意

XFF はあくまで クライアントが自由に書ける普通の HTTP ヘッダー です。curl -H "X-Forwarded-For: 1.2.3.4" のように、誰でも自由にでっちあげられます。

そのため、ざっくりとした目安として次のあたりは意識しておきたいです。

  • アクセス制御や IP 制限に XFF を生のまま使わない: 手前のプロキシが付け直した値だけを信頼する設計にする
  • 左端ではなく "右から N 番目" を取る: 信頼するプロキシの段数を決め打ちして、それより外側の値はログ用にとどめる
  • 可能なら Forwarded(RFC 7239)も併用: for=, by=, proto= が分離されているので、誤読しにくい
  • WAF / CDN のドキュメントを読む: 自社の経路で「どこが XFF を書き換えるか」を 1 度図に起こしておくと、後で楽

このあたりは、製品やバージョンによって挙動が変わるので、本番反映前に必ず一次情報で裏取りしてください。

関連

以上です。

  cards

シェアする

  • このエントリーをはてなブックマークに追加

フォローする