シナプスの技術部システム開発課の小園です。
HTTPヘッダーのX-Forwarded-Forヘッダーについて調査する機会がありましたので、まとめました。
- X-Forwarded-Forヘッダーとは
- XFFヘッダーの例
- XFFヘッダーのセキュリティリスクについて
- XFFヘッダーからのIPアドレスの選択方法
- 複数のXFFヘッダーがあった場合
- ウェブサーバーの設定について
- まとめ
X-Forwarded-Forヘッダーとは
用途
X-Forwarded-For(以下XFF)は、HTTPプロキシーサーバーを経由してウェブサーバーに接続したクライアントの送信元IPアドレスを特定するための事実上の標準ヘッダーです。
developer.mozilla.org
形式
XFFはカンマ区切りのIPアドレスのリストで表されます。リストの左端が元のクライアントを示し、右端が最後のプロキシーサーバーを示します。
X-Forwarded-For: 203.0.113.195, 70.41.3.18, 150.172.238.178
この例では、203.0.113.195がクライアントであり、70.41.3.18が途中のプロキシーサーバー、150.172.238.178が最後のプロキシーサーバーとなります。
標準化の状況
XFFは現行のHTTP仕様書には含まれていません。標準化されたヘッダーとしてForwardedヘッダーがあります。
developer.mozilla.org
XFFヘッダーの例
ウェブサーバー www.hogehoge.jp
へのアクセスがプロキシーサーバー経由で行われた際のサンプルです。
GET / HTTP/1.1 Host: www.hogehoge.jp X-Forwarded-For: 202.95.45.227, 70.41.3.18, 150.172.238.178
このサンプルは、ウェブサーバー(www.hogehoge.jp
)から見た情報です。
アクセス経路は以下の通りです。
graph LR; subgraph ウェブサーバー www.hogehoge.jp; end subgraph プロキシーサーバー 70.41.3.18 -- *1 --> 150.172.238.178; 150.172.238.178 -- *2 --> 150.172.238.177; 150.172.238.177 -- *3 --> www.hogehoge.jp; end subgraph クライアントPC 202.95.45.227 --> 70.41.3.18; end
- 備考
- *1 XFF: 202.95.45.227
- *2 XFF: 202.95.45.227, 70.41.3.18
- *3 XFF: 202.95.45.227, 70.41.3.18, 150.172.238.178
クライアントのIPアドレスは 202.95.45.227
(XFFの左端)です。
このクライアントからのアクセスは、70.41.3.18
、150.172.238.178
、150.172.238.177
の3つのプロキシーサーバーを経由して www.hogehoge.jp
に到達しています。
XFFヘッダーのセキュリティリスクについて
XFF ヘッダーにはセキュリティリスクがあります。
XFFは、HTTPヘッダーであるため、任意の値を設定できます。そのため、なりすましや、誤った設定の可能性があります。
XFFの左端IP 202.95.45.227
は、本当にクライアントのIPアドレスなのかは分かりません。
- ウェブサーバー(
www.hogehoge.jp
)から見た情報
GET / HTTP/1.1 Host: www.hogehoge.jp X-Forwarded-For: 202.95.45.227, 70.41.3.18, 150.172.238.178
- アクセス経路
graph LR; subgraph ウェブサーバー www.hogehoge.jp; end subgraph プロキシーサーバー 150.172.238.177 -- *2 --> www.hogehoge.jp; end subgraph クライアントPC 150.172.238.178 -- *1 --> 150.172.238.177; end
- 備考
- *1 XFF: 202.95.45.227, 70.41.3.18
- *2 XFF: 202.95.45.227, 70.41.3.18, 150.172.238.178
このように、実際の経路とXFFが異なる可能性があります。
XFFヘッダーからのIPアドレスの選択方法
信頼できるIPアドレスの選択方法
信頼できるIPアドレスを選択する方法について説明します。
まず、リモートIPアドレスが信頼できない場合(例:直接インターネット接続されている場合)は、XFFヘッダーの値は信頼できません。そのため、リモートIPアドレスが送信元IPアドレスとなります。
一方で、リモートIPアドレスが信頼できる場合は、XFFヘッダーの右端から信頼できるプロキシーのIPアドレス、または信頼できるプロキシー数(ウェブサーバーから見て、信頼できるプロキシーサーバーの数が決まっている場合)の前にあるIPアドレスが送信元IPアドレスとなります。
以下の例では、70.41.3.18
が信頼できる送信元IPアドレスに該当します。
一方で、202.95.45.227
は偽装可能なIPアドレスです。
- ウェブサーバー(
www.hogehoge.jp
)から見た情報
GET / HTTP/1.1 Host: www.hogehoge.jp X-Forwarded-For: 202.95.45.227, 70.41.3.18, 150.172.238.178
- アクセス経路
graph LR; subgraph ウェブサーバー www.hogehoge.jp; end subgraph 信頼できるプロキシーサーバー 150.172.238.178 -- *2 --> 150.172.238.177; 150.172.238.177 -- *3 --> www.hogehoge.jp; end subgraph 信頼できない\nプロキシーサーバー 70.41.3.18 -- *1 --> 150.172.238.178; end subgraph クライアントPC 202.95.45.227 --> 70.41.3.18; end
- 備考
- *1 XFF: 202.95.45.227
- *2 XFF: 202.95.45.227, 70.41.3.18
- *3 XFF: 202.95.45.227, 70.41.3.18, 150.172.238.178
信頼できないIPアドレスの選択方法
信頼できないIPアドレスを選択する方法について説明します。
これは、セキュリティに関係無い目的の場合になります。
XFFヘッダーの左端から、プライベート/内部では無い最初のIPアドレスが送信元IPアドレスになります。
以下の例では、70.41.3.18
が信頼できない送信元IPアドレスに該当します。
左端の192.168.0.1
はプライベートIPアドレスです。
- ウェブサーバー(
www.hogehoge.jp
)から見た情報
GET / HTTP/1.1 Host: www.hogehoge.jp X-Forwarded-For: 202.95.45.227, 70.41.3.18, 150.172.238.178
- アクセス経路
graph LR; 192.168.0.1 --> 70.41.3.18; 70.41.3.18 -- *1 --> 150.172.238.178; 150.172.238.178 -- *2 --> 150.172.238.177; 150.172.238.177 -- *3 --> www.hogehoge.jp;
- 備考
- *1 XFF: 192.168.0.1
- *2 XFF: 192.168.0.1, 70.41.3.18
- *3 XFF: 192.168.0.1, 70.41.3.18, 150.172.238.178
複数のXFFヘッダーがあった場合
HTTPヘッダーは、カンマで区切ることができる値は、同名のヘッダーを複数含めることができます。
受信側は、ヘッダーが現れた順にカンマで結合した1つのヘッダーとして扱うことができます(Set-Cookieヘッダーは特例)。
以下の例では、結合したヘッダーとして考えます。
- 受信したXFF
X-Forwarded-For: 202.95.45.227, 70.41.3.18 X-Forwarded-For: 150.172.238.178
- 結合したXFF
X-Forwarded-For: 202.95.45.227, 70.41.3.18, 150.172.238.178
ウェブサーバーの設定について
実際にIPアドレスを扱うウェブサーバーでは、XFFに関連する以下のような点を考慮する必要があります。
- XFFヘッダーのIPアドレスでアクセス制御をするには?
- ウェブサーバーには、IPアドレスに基づいて処理する箇所を、XFFを考慮することなく設定できるための仕組みがあります。
- リバースプロキシーを用意したい時はどうすればいいの?
- リバースプロキシーとして構築するには、XFFを適切に設定する必要があります。
ウェブサーバーには、リバースプロキシーとして適切に構築する方法があります。
- リバースプロキシーとして構築するには、XFFを適切に設定する必要があります。
Apache
XFFヘッダーのIPアドレスでアクセス制御をするには?
Apacheモジュールのmod_remoteip
を使います。
mod_remoteip - Apache HTTP Server Version 2.4
- 設定例
LoadModule remoteip_module modules/mod_remoteip.so RemoteIPHeader X-Forwarded-For RemoteIPInternalProxy 192.168.0.0/16 RemoteIPInternalProxy 150.172.238.177 150.172.238.178
LoadModule
はデフォルト設定でロードされる場合がありますので、その場合はこの設定は不要です。RemoteIPHeader
はIPアドレスのリストが設定されたヘッダーを指定します。
通常は、X-Forwarded-For
ですが、X-Real-IP
のような別のヘッダーに設定されている場合もあります。RemoteIPInternalProxy
は信頼できるIPアドレスを設定します。
リバースプロキシーを用意したい時はどうすればいいの?
Apacheモジュールのmod_proxy
のProxyAddHeaders
ディレクティブで設定します。
mod_proxy - Apache HTTP Server Version 2.4
- 設定例
ProxyAddHeaders On
ProxyAddHeaders
ディレクティブをOnにすることで、リバースプロキシ時に、X-Forwarded-For、X-Forwarded-Host、X-Forwarded-Serverをバックエンドサーバーに渡します。- デフォルト値はOnです。明示的にOffにしない限り、処理されます。
nginx
XFFヘッダーのIPアドレスでアクセス制御をするには?
nginxのngx_http_realip_module
モジュールを使います。
Module ngx_http_realip_module
real_ip_header X-Forwarded-For; real_ip_recursive on; set_real_ip_from 192.168.0.0/16; set_real_ip_from 150.172.238.177; set_real_ip_from 150.172.238.178;
real_ip_header
は、IPアドレスのリストが設定されたヘッダーを指定します。real_ip_recursive
は、onにすることで、再帰的にIPアドレスを検査します。
複数のプロキシーサーバーを経由している場合には、onにする必要があります。set_real_ip_from
は信頼できるIPアドレスを設定します。
リバースプロキシーを用意したい時はどうすればいいの?
nginxのngx_http_proxy_module
モジュールのproxy_set_header
を使います。
Module ngx_http_proxy_module
nginxがフロントエンドの場合
nginxがフロントエンド(インターネットに露出している)の場合には、リモートIPアドレスから送られてきたXFFを無視して、リモートIPアドレスをXFFとして設定します。
信頼できないIPアドレスから送信されてきたXFFは無視するのがセキュリティとして正しい設定になります。
proxy_set_header X-Forwarded-For $remote_addr;
nginxが中継プロキシーサーバーの場合
nginxが中継プロキシーサーバーの場合には、上流プロキシーサーバーから受け取ったXFFに上流プロキシーサーバーのIPアドレスを付加して設定します。
$remote_addr
という変数もありますが、この変数は、real_ip_header
などで書き換えられている場合がありますので、$realip_remote_addr
を使います。
$proxy_add_x_forwarded_for
という変数もありますが、この変数の値は、$http_x_forwarded_for, $remote_addr
であるため、$remote_addr
が書き換わっている場合があります。
proxy_set_header X-Forwarded-For "$http_x_forwarded_for, $realip_remote_addr";
まとめ
- XFFヘッダーは、HTTPプロキシーサーバーを経由したクライアントの IP アドレスを特定するための事実上の標準です。
- XFFヘッダーは、任意の値を設定できるため、なりすましや誤った設定のリスクがあります。そのため、適切な方法でIPアドレスを選択する必要があります。
- ウェブサーバー(Apache, nginx)には適切な方法でIPアドレスを選択するための仕組みが提供されています。