ロードバランサやクラウドWAF経由でX-Forwarded-Forを利用する場合のApache設定

WEBサービスの話。サーバーにたどり着くまでにAWS-ELB等のロードバランサやクラウド型のWAFを経由する場合、正確なアクセス元IPを取得するには`X-Forwarded-For`(今後XFFと呼ぶ)というリクエストヘッダーを見なければならない。
単純に見れば良いというわけではない事が分かったので図解。Apache設定(.htaccess)でゴニョゴニョしてアプリはXFFを見ればよい状態にする事が目的。そもそもアプリで解析して見れば良いのでは？という話は置いておく（一応、環境依存情報はなるべくミドルウェア設定に逃がす思想下の場合では有効）

> ※ ロードバランサ・クラウドWAF経由の正しい経路外のアクセスかどうかも判断することは難しい事が後々分かってくるので、正しい経路外のアクセスは絶たれている事が前提。まあ、そもそもその時点で負荷や攻撃から守られていないという事のなので何卒。

## クライアント ⇒ ロードバランサ経由 ⇒ サーバー行

![mermaidjs.github.io_mermaid-live-editor_ (2).png](https://qiita-image-store.s3.amazonaws.com/0/65983/ee937f4f-02a0-1017-1b12-a53c0170e5de.png)
Designed by [Mermaid.js](https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ3JhcGggVERcbnN1YmdyYXBoIOOCr-ODqeOCpOOCouODs-ODiFxuICAgIElbXCI8aDI-8J-YieODluODqeOCpuOCtkE8L2gyPklQOiAxLjEuMS4xPGJyPuaZrumAmuOBruOCouOCr-OCu-OCuVwiXVxuICAgIEFbXCI8aDI-8J-YieODluODqeOCpuOCtkI8L2gyPklQOiAxLjEuMS4xPGJyPuafkEHnq6_mnKvjg5bjg6njgqbjgrbpq5jpgJ_ljJbnrYnjga7jgqLjgq_jgrvjgrlcIl1cbiAgICBKW1wiPGgyPvCfmIjjg5bjg6njgqbjgrZDPC9oMj5JUDogMS4xLjEuMTxicj5YRkbjg5jjg4Pjg4DjgpLmlLnjgZbjgpPjgZfjgabjgqLjgq_jgrvjgrlcIl1cbmVuZFxuc3ViZ3JhcGgg5aSW6YOo44K144O844OT44K5XG4gICAgQTIoXCI8aDI-PGkgY2xhc3M9J2ZhIGZhLXJhbmRvbSc-PC9pPiBTUERZIFByb3h5562JPC9oMj5JUDogMi4yLjIuMlwiKVxuZW5kXG5zdWJncmFwaCDmj5DkvpvjgrXjg7zjg5PjgrlcbiAgICBGKFwiPGgyPjxpIGNsYXNzPSdmYSBmYS1jbG91ZCc-PC9pPiDjg63jg7zjg4njg5Djg6njg7PjgrU8L2gyPklQOiA0LjQuNC40XCIpXG4gICAgQyhcIjxoMj48aSBjbGFzcz0nZmEgZmEtY2xvdWQnPjwvaT4g44Ot44O844OJ44OQ44Op44Oz44K1PC9oMj5JUDogNC40LjQuNFwiKVxuICAgIEgoXCI8aDI-PGkgY2xhc3M9J2ZhIGZhLWNsb3VkJz48L2k-IOODreODvOODieODkOODqeODs-OCtTwvaDI-SVA6IDQuNC40LjRcIilcbiAgICBEW1wiPGgyPjxpIGNsYXNzPSdmYSBmYS1zZXJ2ZXInPjwvaT4g44K144O844OQ44O8PC9oMj5cIl1cbmVuZFxuXG5JIC0tPiBGXG5GIC0tPnxcIlhGRjogPGI-MS4xLjEuMTwvYj5cInwgRFxuXG5BIC0tPiBBMlxuQTIgLS0-fFhGRjogMS4xLjEuMXwgQ1xuQyAtLT58XCJYRkY6IDEuMS4xLjEsIDxiPjIuMi4yLjI8L2I-XCJ8IERcblxuSiAtLT58XCI8aDI-PGkgY2xhc3M9J2ZhIGZhLWV4Y2xhbWF0aW9uLXRyaWFuZ2xlJz4g5pS544GW44KTXCIgWEZGOiA5LjkuOS45PC9oMj58IEhcbkggLS0-fFwiWEZGOiA5LjkuOS45LCA8Yj4xLjEuMS4xPC9iPlwifCBEIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifX0)

- ブラウザAは一般的なピーポー的な人。XFFはそのまま見ればよい。
- ブラウザBはたまにやってくる人。不正っぽいからと除外してはいけない。<br>（提供サービスエンドポイントへの接続元IPを正とする）
- ブラウザCは明らかに攻撃する気満々な人。XFFヘッダを改ざんしてアクセス。

サーバーにたどり着いた時には、XFFを見ると金魚のフン状態ですが、要は**一番後ろ**を見ればよい。
サーバーのApacheに以下設定を入れると正しいIPで詰め替えられるはず。（間違っていたらご指摘ください。）

```apache:Apache(httpd.conf/.htaccess)
    SetEnvIf X-Forwarded-For ", " multiforward
    RewriteCond %{HTTP:X-Forwarded-For} ,\ (.+)$
    RewriteRule .* - [E=CENV_CLIENT_ADDR:%1]
    RequestHeader set X-Forwarded-For "%{CENV_CLIENT_ADDR}e" env=multiforward
```

## クライアント ⇒ クラウドWAF経由 ⇒ ロードバランサ経由 ⇒ サーバー行

![mermaidjs.github.io_mermaid-live-editor_ (3).png](https://qiita-image-store.s3.amazonaws.com/0/65983/2f12cdde-247c-0d8a-f089-4458ae52e6a7.png)
Designed by [Mermaid.js](https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ3JhcGggVERcbnN1YmdyYXBoIOOCr-ODqeOCpOOCouODs-ODiFxuICAgIElbXCI8aDI-8J-YieODluODqeOCpuOCtkE8L2gyPklQOiAxLjEuMS4xPGJyPuaZrumAmuOBruOCouOCr-OCu-OCuVwiXVxuICAgIEFbXCI8aDI-8J-YieODluODqeOCpuOCtkI8L2gyPklQOiAxLjEuMS4xPGJyPuafkEHnq6_mnKvjg5bjg6njgqbjgrbpq5jpgJ_ljJbnrYnjga7jgqLjgq_jgrvjgrlcIl1cbiAgICBKW1wiPGgyPvCfmIjjg5bjg6njgqbjgrZDPC9oMj5JUDogMS4xLjEuMTxicj5YRkbjg5jjg4Pjg4DjgpLmlLnjgZbjgpPjgZfjgabjgqLjgq_jgrvjgrlcIl1cbmVuZFxuc3ViZ3JhcGgg5aSW6YOo44K144O844OT44K5XG4gICAgQTIoXCI8aDI-PGkgY2xhc3M9J2ZhIGZhLXJhbmRvbSc-PC9pPiBTUERZIFByb3h5562JPC9oMj5JUDogMi4yLjIuMlwiKVxuZW5kXG5zdWJncmFwaCDmj5DkvpvjgrXjg7zjg5PjgrlcbiAgICBFKFwiPGgyPjxpIGNsYXNzPSdmYSBmYS1jbG91ZCc-PC9pPiDjgq_jg6njgqbjg4lXQUbnrYk8L2gyPklQOiAzLjMuMy4zXCIpXG4gICAgQihcIjxoMj48aSBjbGFzcz0nZmEgZmEtY2xvdWQnPjwvaT4g44Kv44Op44Km44OJV0FG562JPC9oMj5JUDogMy4zLjMuM1wiKVxuICAgIEcoXCI8aDI-PGkgY2xhc3M9J2ZhIGZhLWNsb3VkJz48L2k-IOOCr-ODqeOCpuODiVdBRuetiTwvaDI-SVA6IDMuMy4zLjNcIilcbiAgICBGKFwiPGgyPjxpIGNsYXNzPSdmYSBmYS1jbG91ZCc-PC9pPiDjg63jg7zjg4njg5Djg6njg7PjgrU8L2gyPklQOiA0LjQuNC40XCIpXG4gICAgQyhcIjxoMj48aSBjbGFzcz0nZmEgZmEtY2xvdWQnPjwvaT4g44Ot44O844OJ44OQ44Op44Oz44K1PC9oMj5JUDogNC40LjQuNFwiKVxuICAgIEgoXCI8aDI-PGkgY2xhc3M9J2ZhIGZhLWNsb3VkJz48L2k-IOODreODvOODieODkOODqeODs-OCtTwvaDI-SVA6IDQuNC40LjRcIilcbiAgICBEW1wiPGgyPjxpIGNsYXNzPSdmYSBmYS1zZXJ2ZXInPjwvaT4g44K144O844OQ44O8PC9oMj5cIl1cbmVuZFxuXG5JIC0tPiBFXG5FIC0tPnxYRkY6IDEuMS4xLjF8IEZcbkYgLS0-fFwiWEZGOiA8Yj4xLjEuMS4xPC9iPiwgMy4zLjMuM1wifCBEXG5cbkEgLS0-IEEyXG5BMiAtLT58WEZGOiAxLjEuMS4xfCBCXG5CIC0tPnxYRkY6IDEuMS4xLjEsIDIuMi4yLjJ8IENcbkMgLS0-fFwiWEZGOiAxLjEuMS4xLCA8Yj4yLjIuMi4yPC9iPiwgMy4zLjMuM1wifCBEXG5cbkogLS0-fFwiPGgyPjxpIGNsYXNzPSdmYSBmYS1leGNsYW1hdGlvbi10cmlhbmdsZSc-IOaUueOBluOCk1wiIFhGRjogOS45LjkuOTwvaDI-fCBHXG5HIC0tPnxYRkY6IDkuOS45LjksIDEsMSwxLDF8IEhcbkggLS0-fFwiWEZGOiA5LjkuOS45LCA8Yj4xLjEuMS4xPC9iPiwgMy4zLjMuM1wifCBEXG4iLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9fQ)

サーバーは何を見ればよいか？　要は**後ろから提供サービス内で経由された数（上記の例では2つ目）**を見ればよい。
サーバーのApacheに以下設定を入れると正しいIPで詰め替えられるはず。（間違っていたらご指摘ください。）

```apache:Apache(httpd.conf/.htaccess)
    SetEnvIf X-Forwarded-For ", " multiforward
    RewriteCond %{HTTP:X-Forwarded-For} ([0-9\.]+)(,\ [0-9\.]+){1}$
    RewriteRule .* - [E=CENV_CLIENT_ADDR:%1]
    RequestHeader set X-Forwarded-For "%{CENV_CLIENT_ADDR}e" env=multiforward
```

2行目最後の`{1}`の数字は後ろから飛ばす数。後ろから２つ目の場合は「後ろから１つ飛ばす」という意味で「1」を指定している。