26 Jul 2016, 21:59

PHPでhttpヘッダー、x-forwarded-forを受け取る

もともとApach+PHPで動作していたシステムに、リバースプロキシ(Nginx)を前段に挟むことになった。理由は、もともと社内ネットワークでのみ利用するシステムだったのだが、インターネットの外からも利用することになり、インターネットからの入り口にリバースプロキシを導入したから。
つまり、Nginx->Apache->PHPという構成になった。
よくあることだが、Apacheからみるとすべてリバースプロキシから通信がきているので、 接続元のIPアドレスがすべてリバースプロキシのものになる。

HTTPヘッダーに接続元のIPアドレスを追加しアプリ側(PHP)で受け取る方法をかく。

リバースプロキシ側でHTTPヘッダー追加

まず、そもそもデフォルトのNginxの設定では接続元のIPアドレスをHTTPヘッダーに含まれない。
ググればすぐに設定方法自体はでてくる。
X-Forwarded-Forというヘッダー名にNginxでもっている変数$proxy_add_x_forwarded_forを追加する。

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 

設定は簡単なんだけど、そもそもX-Forwarded-Forなんていうヘッダーはもともとあったか?と疑問に思い調べてみると。

X-Forwarded-For (XFF) とは、HTTPヘッダフィールドの一つ。HTTPプロキシサーバまたは負荷分散装置(ロードバランサ)を経由してウェブサーバに接続するクライアントの送信元IPアドレスを特定する際のデファクトスタンダードである。 (略)RFCの標準的なヘッダフィールドではないが、IETFのネットワーク作業部会 (Network Working Group) は2011年10月より同種のHTTPヘッダForwardedの標準化作業を開始した[1]。

なるほど、RFCの標準ではないけど、一般的なものなんですね。

phpでX-Forwarded-Forを受け取る

リバースプロキシで'X-forwarded-For'という名前のHTTPヘッダーを追加したので、そのまま取得することをやってみるが、うまくいかなかった。これはPHPのサーバ変数の仕様の問題だ。

echo $_SERVER['X-Forwarded-For'];

サーバ変数をvar_dumpを使って中身を確認してみると、 HTTPが先頭についてて、すべて大文字になってて、ハイフンがアンスコに変わっていることが確認できた。
```php string(12) "192.168.33.1" ...... } ``` ためしにgetallheadersという関数で生のヘッダーの状態を確認してみると、想定通りでした。 つまりサーバ変数に格納するタイミングで、名前が変わるということです。 ```php string(12) "192.168.33.1" ...... } ```

tcpdumpで生のパケットを確認してみる

もう結果は見えているのですが、気になったのでtcpdumpで生パケットの状態を確認してみた。

$ sudo yum install tcpdump
$ tcpdump dst port 80 -X

# ながいんで適当に端折りました
11:04:01.883209 IP 10.0.2.15.43038 > 192.168.0.10.54655: Flags [.], seq 802:1603, ack 1, win 14600, length 1460
     (略)
     0x0000:  4500 0355 c705 0000 3706 24ca adc2 265f  1.0..X-Forwarded
     0x0010:  c0a8 000a 0050 d57f 51ad 1e62 e596 78a4  -For:.192.168.33
     0x0020:  8018 0137 8dbe 0000 0101 080a d1dc c19e  .1..Host:.xxxxxx 

いたいた。
Nginxからプロキシされるときはちゃんとヘッダー名は"X-Forwarded-For "になっていること確認。

任意の適当なHTTPヘッダーつけてみた

それでは、X-Forwarded-For以外の任意のHTTPヘッダーをつけた場合も同様になるのか確認してみます。 Nginxにて、’my-header’という名前でヘッダーを追加してPHP側で受け取ります。

proxy_set_header my-header 'hogefugafoobar'; 

‘my-header’が’HTTP_MY_HEADER’に変わっていることが確認できた。

var_dump($_SERVER);

# array(35) { ["HTTP_MY_HEADER"] => string(14) "hogefugafoobar" ...... }

関連する記事はこちら
  • NginxのログをFluentdでDynamoDBへ送る (2017/09/03)
  • Nginxの仕組みについて入門 (2016/06/04)
  • 【VPS1台でインフラ勉強】サーバ複数台構成、Nginxでリバースプロキシ構築 (2014/10/09)
  • comments powered by Disqus
    このエントリーをはてなブックマークに追加