前置き
相当古いファイアウォール(以下「FW」)などを利用していると、パケットが機器を通過するとSrcIPがFWのものに変わり、X-Forwarded-ForヘッダにエンドユーザのIPが入るような仕組みがありました。その後次世代FWなどと呼ばれる機器の進化によってSrcIPを変えずに、アプリケーションサーバまで通信が到達するような仕組みを聞くようになりました。しかし、SaaS型WAFなど機器とアプリケーションサーバ間で物理的な接続がない(インターネットを経由するなど)場合、通信の仕組み上SrcIPを変え、X-Forwarded-ForにエンドユーザのSrcIPを格納する必要があります。
あるアプリケーションサーバでエンドユーザのSrcIPによって制御などを掛ける機能があれば、X-Forwarded-Forの値を参照して処理をしなければなりません。通常時は問題ないですが、SaaS型WAFが障害で停止してしまった場合、WAFを経由しない設定に戻す必要がありX-Forwarded-Forを参照しても、ヘッダ自体がなくエンドユーザのIPはSrcIPに格納されています。そのため、Webサーバ(Apache)でアプリケーションサーバへ通信を転送する際、X-Forwarded-Forヘッダがない場合は、障害発生時とみなしてSrcIPの値をコピーしてX-Forwarded-Forヘッダを付けるという設定を入れます。そうすることで、アプリケーションサーバは通常時でも、障害時でもX-Forwarded-Forヘッダの値を参照すれば問題ありません。
Apacheの設定(本設定はIPv4限定です)
・X-Forwarded-Forヘッダがあり、IPアドレスが格納されている場合、何もしない
・X-Forwarded-Forヘッダがあり、ありえない値が格納されている場合、SrcIPを入れる
・X-Forwarded-Forヘッダがない場合、SrcIPの値をX-Forwarded-Forヘッダを作って入れる
※X-Forwarded-ForヘッダはApacheが転送する際に付けられるため、転送先で参照できます。
バージョン
[Tabit@apache httpd]$ apachectl -version
Apache/2.4.6 (CentOS)
設定ファイル
#log format
LogFormat "%h %{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
#this post settings
SetEnvIf X-Forwarded-For "([1-9]|[1-9][0-9]|[1-9][0-9][0-9]).([0-9]|[1-9][0-9]|[1-9][0-9][0-9]).([0-9]|[1-9][0-9]|[1-9][0-9][0-9]).([1-9]|[1-9][0-9]|[1-9][0-9][0-9])" xff
RewriteEngine On
RewriteRule ^(.*) - [E=ENDUSER_IP:%{REMOTE_ADDR},L]
RequestHeader set X-Forwarded-For "%{ENDUSER_IP}e" env=!xff
アクセス情報とアクセスログ
122.223.134.39 122.223.134.39 - - [20/Apr/2016:23:48:33 +0900] "GET / HTTP/1.1" 200 91 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36"
122.223.134.39 8.8.8.8 - - [20/Apr/2016:23:47:12 +0900] "GET / HTTP/1.1" 200 91 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36"
X-Forwarded-Forにありえない値を入れてアクセス(攻撃者?)
122.223.134.39 122.223.134.39 - - [20/Apr/2016:23:50:34 +0900] "GET / HTTP/1.1" 200 91 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36"
こんな状況はあまりないと存じますが、仮にSaaS系サービスが障害発生して正常に動かない場合、アプリケーションへアクセスできなくなってしまいます。ケースの一つとして想定しておき、アプリケーション側でも対応を済ませて、障害発生時であっても冷静に対処したいですね。(あらゆる事態に対応できるように作り込むのは、困難だとは思いますが)