[31] [DFN[[CODE(HTTP)@en[[[X-Forwarded-For:]]]]]] [[ヘッダー]]は、
[[串]] ([[順串]]や[[逆串]]) が直接の[[クライアント]]の[[IPアドレス]]を保存し、
次以降の[[ホップ]]へと伝えるためのものです。

* 仕様書

[REFS[
- [19] [CITE@en[RFC 7239 - Forwarded HTTP Extension]] ([TIME[2014-09-07 05:21:07 +09:00]] 版) <https://tools.ietf.org/html/rfc7239#section-5.2>
- [26] [CITE@en[RFC 7239 - Forwarded HTTP Extension]] ([TIME[2014-09-07 05:21:07 +09:00]] 版) <https://tools.ietf.org/html/rfc7239#section-7.4>
]REFS]

* 構文

[11] [[IPv6アドレス]]は ([[括弧]]で括るなどせずに) 直接書くことができるようです。

;; [12] [[Squid]] などが対応しているようです。[[鯖側Webアプリケーション]]の類では
[[IPv4アドレス]]にしか対応していないことが多々あります。

[13] [CODE(HTTP)@en[[[X-Forwarded-For:]]]] 欄を複数含めることにより (あるいは [CODE(HTTP)[[[,]]]]
によって連結することにより) 多段の[[串]]の通過を表現できます。

;; [14] [[鯖側Webアプリケーション]]の類ではこれに対応していないこともあります。

* 順序

[6] [[Wikipedia]] の説明によると先頭 (前) ほど[[クライアント]]側、末尾 (後) ほど[[鯖]]側の [[IPアドレス]]を表していることになっているようです。

[39] [CITE[[[MDN]]]] も同じ順序を示しています。 [SRC[>>37]]

[38] 実際には必ずしもこの順序が守られているわけでは無いようです。

[40] [CITE[[[MDN]]]] は詳しい解説を載せていますが [SRC[>>37]]、
その根拠をまったく示していません。

[41] そもそもこの機能は[[仕様書]]もなく慣習的に使われてきたもので、
どのように使われるべきか規範的で信頼できる根拠が何も存在していないのです。

[42] 
どのような順序にするのが正しいかという問題とは別に (しかし密接に関わる問題として)、
[[IPアドレス]]を1つ拾って何かをしたいとき、
どれを選ぶのが適切なのか、という問題があります。
[SRC[>>15]]

[43] 
これも仕様が定まっていない上に、「用途による」としか言いようがないので答えるのが難しい。



[REFS[
- [37] 
[CITE@en-US[X-Forwarded-For - HTTP | [[MDN]]]], [TIME[2022-09-10T01:00:23.000Z]], [TIME[2022-09-11T06:53:32.899Z]] <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For>
]REFS]

[15] [CITE[Ruby - Rack::Request#hostがX-Forwarded-Hostの最後のプロキシホストを返す理由 - Qiita ''''''[''''''キータ'''''']'''''']]
( ([TIME[2014-01-08 07:20:40 +09:00]] 版))
<http://qiita.com/mechamogera/items/32db29aa0db91df704ba>


* 実装

[36] [[さくらインターネット]]の共有レンタルサーバーでは、
[DFN[[CODE(HTTP)@en[[[X-Sakura-Forwarded-For:]]]]]]
([CODE(CGI)@en[[[HTTP_X_SAKURA_FORWARDED_FOR]]]]) が使われるようです。

[10] [CODE(HTTP)@en[[[X-Client-IP:]]]], [CODE(HTTP)@en[[[CF-Connecting-IP:]]]],
[CODE(HTTP)@en[X-Real-IP:]]
といった[[ヘッダー]]が使われることもあります。

* [CODE(HTTP)@en[Forwarded:]] ヘッダー [CODE(HTTP)@en[for]] 引数

[20] [CODE(HTTP)@en[[[Forwarded:]]]] [[ヘッダー]]の [DFN[[CODE(HTTP)@en[[[for]]]]]]
[[引数]]は、[[クライアント]]についての情報を表します [SRC[>>19]]。

** 値

[24] 値の構文は[[節点識別子]]です [SRC[>>19]]。

[FIG(railroad)[
= [[節点識別子]]
]FIG]

[21] [[既定]]の設定では[[難読化識別子]]を使う[['''べきです''']] [SRC[>>19]]。

[22] 必要ならかわりに[[IPアドレス]] (や場合によっては[[ポート番号]])
を指定しても構いません [SRC[>>19]]。

[23] [CODE(HTTP)@en[[[unknown]]]] としても構いません [SRC[>>19]]。

* 歴史

** 誕生

[4] [CODE(HTTP)@en[[[X-Forwarded-For:]]]] は [[Squid]] が使い始めました。

[REFS[
- [1] ''Nonstandard HTTP Headers'' <http://web.archive.org/web/20020610043404/http://www.dais.is.tohoku.ac.jp/~kabe/WWW/nonstdhdr.html#X-Forwarded-For>
]REFS]


>X-Forwarded-For: [VAR[clientIPaddr]]|unknown
>Squid が最初。 他のproxyがつけているのはSquidのマネ。 HTTP DraftがForwarded:からVia: へ変更されたのを受けて、 クライアントアドレスをどこかに残すために新設されました。
(changelogヨリ)
-1.0.beta1:	Forwarded: 追加 (User-Agent: ... via ... そのまま)
-1.1.alpha17:	User-Agent: via.. 廃止、Forwarded:のみ
-1.1.beta21:	Forwarded->Via
-1.1.beta24:	X-Forwarded-For 新設
>この頃の Squid はバージョンアップがやたら激しく、 alphaだbetaだreleaseだといった違いにあまり意味はありません。

>Forwarded: by [VAR[proxy-URI]] [([VAR[product]])] [for [VAR[client-FQDN]]]
>draft-ietf-http-v10-spec-01.txt および draft-ietf-http-v11-spec-01.txt までの HTTP-draft に出現。 標準化に際しては 「冗長である」 という理由から Via: に置き換わっています。 "for ..." 部分は Via: から削られたため、Squid では代わりに X-Forwarded-For ヘッダを新設しました。 (当時まじめにDraft等を追っかけていたのは Squid くらいだったような気が)

** [CODE(HTTP)@en[Forwarded-For:]] ヘッダー

[29] [CODE(HTTP)@en[[[Forwarded-For:]]]] として標準化することが提案されました [SRC[>>28]]。

[REFS[
- [28] [CITE@en[draft-petersson-forwarded-for-00 - Forwarded HTTP Extension]] ([TIME[2014-10-16 18:50:28 +09:00]] 版) <https://tools.ietf.org/html/draft-petersson-forwarded-for-00>
]REFS]

** [CODE(HTTP)@en[Forwarded:]] ヘッダー

[30] >>28 は次の版で現在とほぼ同じ [CODE(HTTP)@en[[[Forwarded:]]]] [[ヘッダー]]に拡張されました。

[25] [[RFC 7239]] で [CODE(HTTP)@en[[[X-Forwarded-For:]]]] と同様の内容を持つ
[CODE(HTTP)@en[[[Forwarded:]]]] [[ヘッダー]]の [CODE(HTTP)@en[[[for]]]] [[引数]]
[SRC[>>19]] が追加されました。

* 例

[EG[
[27] [[IPv6アドレス]]が含まれることもあります [SRC[>>26]]。

[PRE(HTTP code)[
X-Forwarded-For: 192.0.2.43, 2001:db8:cafe::17
]PRE]
]EG]

* メモ

[REFS[
- [2]
[CITE@en[Content Transformation Guidelines 1.0]] ([TIME[2008-08-01 01:46:12 +09:00]] 版) <http://www.w3.org/TR/2008/WD-ct-guidelines-20080801/#sec-additional-headers>
- [3] [CITE@en[Guidelines for Web Content Transformation Proxies 1.0]]
( ([TIME[2010-10-22 17:20:31 +09:00]] 版))
<http://www.w3.org/TR/2010/NOTE-ct-guidelines-20101026/#sec-additional-headers>
]REFS]

[5] [CITE@en[X-Forwarded-For - Wikipedia, the free encyclopedia]]
( ([TIME[2012-02-16 13:54:05 +09:00]] 版))
<http://en.wikipedia.org/wiki/X-Forwarded-For>

[7] [CITE[suz-lab - blog: すでに"X-Forwarded-For"ヘッダのついたHTTPリクエストがELBを経由すると]]
( ([TIME[2012-02-26 09:13:31 +09:00]] 版))
<http://blog.suz-lab.com/2011/06/x-forwarded-forhttpelb.html>

[8] [CITE[リバースプロキシ環境下のapacheではmod_extract_forwardedよりもやっぱりmod_rpaf? - うまい棒blog]]
( ([TIME[2012-02-26 12:29:26 +09:00]] 版))
<http://d.hatena.ne.jp/hogem/20090622/1245675445>

[9] [CITE@en[mod_remoteip - Apache HTTP Server]]
( ([TIME[2012-01-10 03:11:16 +09:00]] 版))
<http://httpd.apache.org/docs/2.3/mod/mod_remoteip.html>


[16] [CITE[HTTP - XFF - Qiita]]
( ([TIME[2014-02-21 10:00:39 +09:00]] 版))
<http://qiita.com/wakaba@github/items/cf8730ca3d75b28d844a>


[44] 
HTTP 
[CODE[X-Forwarded-For:]] ヘッダー 
([CODE[$ENV{[[HTTP_X_FORWARDED_FOR]]}]]) のよくある話のまとめ

- reverse proxy よりも外側で付けられることがあるので、無条件で信頼しても良いわけではない
- reverse proxy より外で付けられた XFF は reverse proxy で落としても良いかもしれないが、
-- 落とす設定を忘れたり、いつのまにか無効になってたりすると困るので、値を信頼したいなら相応の予防措置が必要
-- XFF にはそれなりに有用な情報が詰まってるので最低でも reverse proxy のログには残したいし、アプリケーションサーバーで取りたくなることもあるかもしれない (しないかもしれない)
- reverse proxy よりも内側で付けられることがあるので (多段になっている場合)、ヘッダーや値が1つだけとは限らない
-- 最初は1つだけだと思っていたのに、後からキャッシュサーバーを挟む必要がでてきたら・・・?
- XFF が既にあるときに、前につける串と後につける串がある
-- なので最初とか最後とかを拾うだけではだめ
- データセンター内のプライベートIPアドレスを除去するという対策が提案されてる
-- なお、アプリケーションサーバー → キャッシュサーバー → reverse proxy → アプリケーションサーバーみたいな内部から内部への経路だと、グローバルアドレスの前にも後にも内部IPアドレスが付いた XFF になったりする
-- アプリケーションサーバー → proxy → アプリケーションサーバーのような経路を使うとグローバルIPアドレスが無い XFF になるので、それがあり得るならそれなりにケアが必要
- 最外 reverse proxy で相手のアドレスを独自ヘッダーに入れて XFF じゃなくてそちらを使う、という対策が提案されている
-- 独自ヘッダーが既に付けられている場合は落とす必要はやはりある
- ちなみに XFF が最も広く使われているが、他にも同目的のヘッダーがある
-- [CODE[X-Client-IP:]]、[CODE[X-Sakura-Forwarded-For:]]、[CODE[CF-Connecting-IP:]] など
-- IETF は [CODE[Forwarded:]] ヘッダーを新たに開発したが、本稿にまとめた問題を解決するものではない
-- 混在するとどれを採用するべきか問題がますます複雑になるので、 reverse proxy の類を作るなら、できるだけ XFF を採用したい
 




[17] [CITE@en-US[How does CloudFlare handle HTTP Request headers? – CloudFlare Support]]
( ([TIME[2014-05-09 04:16:11 +09:00]] 版))
<https://support.cloudflare.com/hc/en-us/articles/200170986-How-does-CloudFlare-handle-HTTP-Request-headers->

[18] [CITE@en[draft-nottingham-surrogates-00 - Requirements for Demand-Driven Surrogate Origin Servers]]
( ([TIME[2014-10-06 08:47:36 +09:00]] 版))
<http://tools.ietf.org/html/draft-nottingham-surrogates-00#section-3.7.1>

[32] [CITE@ja[X-Forwarded-For Header :: Add-ons for Firefox]]
( ([TIME[2014-10-26 06:17:51 +09:00]] 版))
<https://addons.mozilla.org/ja/firefox/addon/x-forwarded-for-header/>

[33] [CITE[SOL4816 - Using the X-Forwarded-For HTTP header to preserve the original client IP address for traffic translated by a SNAT]]
( ([TIME[2014-10-26 06:28:55 +09:00]] 版))
<https://support.f5.com/kb/en-us/solutions/public/4000/800/sol4816.html>

[34] [CITE@en[Guidelines for Web Content Transformation Proxies 1za]]
( ([TIME[2010-04-13 17:10:20 +09:00]] 版))
<http://www.w3.org/2005/MWI/BPWG/Group/TaskForces/CT/editors-drafts/Guidelines/100402#sec-additional-headers>

[FIG(quote)[
[FIGCAPTION[
[35] [CITE@en[mod_proxy - Apache HTTP Server Version 2.4]]
([TIME[2015-02-15 17:51:02 +09:00]] 版)
<http://httpd.apache.org/docs/current/en/mod/mod_proxy.html#x-headers>
]FIGCAPTION]

> X-Forwarded-For
> The IP address of the client.

]FIG]