シナプス技術者ブログ

シナプスの技術者公式ブログ。インターネットで、鹿児島の毎日を笑顔にします。

X-Forwarded-For ヘッダーについて

シナプスの技術部システム開発課の小園です。
HTTPヘッダーのX-Forwarded-Forヘッダーについて調査する機会がありましたので、まとめました。

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.18150.172.238.178150.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を適切に設定する必要があります。
      ウェブサーバーには、リバースプロキシーとして適切に構築する方法があります。

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_proxyProxyAddHeadersディレクティブで設定します。
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アドレスを選択するための仕組みが提供されています。