あーかいぶすハイディフィニション

ここはもう更新しとらんのじゃ

Nginx 利用時に、X-Forwarded-For にアクセス元 IP が格納されているのに、Rails のログには 127.0.0.1 がアクセス元 IP と記録される

2013/8/2
【速報】やっぱだめだった、この箇所実装した人どういう意図で作ったんだ……。

VPN 越しにウェブサーバにアクセスする環境で、Remote_Addr・X-Forwarded-For それぞれ HTTP のヘッダに値が入ってるのに、Rails のログは全て 127.0.0.1 からのアクセスです!とか言い出す事案。ウェブ兼 API サーバとしてリリースしてて、構築終わってひと月以上たってから、担当のコーダに「これ(API のアクセス)全部 127.0.0.1 で Allow して対応してんだけど、(セキュリティ的に)まずいんじゃねーの?」とか言われて死にたくなった。そういう事はもっと早く言え頼むから。


というわけで、このへんを見て、開発室の暫定CTO()も巻き込んでみた結果。
ActionDispatch::RemoteIp::GetIp
Proxyサーバーの有無にかかわらずクライアントIPアドレスを取得する - Qiita
プロキシ経由時のリモートアドレスについて! - mk-mode BLOG
willcomの高速化サービスでIP spoofing attackエラー - odeの開発メモ日記

結局 Nginx に HTTP_CLIENT_IP を設定することで回避した。こんな改ざんしやすい値を設定するとか信じられない!俺はアトリームに帰るぞ!

    location @app {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Client-IP $remote_addr; ##これ追加した##
        proxy_set_header Host $http_host;
        proxy_redirect off;

        if (!-f $request_filename) {
          proxy_pass http://127.0.0.1:3000;
          break;
        }
    }

そもそも Nginx のアクセスログに $proxy_add_x_forwarded_for 出力させるとアクセスしてきた IP 入ってるし、Rails のログにタグ出しして IP 表示させるとちゃんと撮れてるんすよ。けど、request.remote_ip で取得すると 127.0.0.1、意味わかんねー。

なお問題が発生した1

HTTP_CLIENT_IP と HTTP_X_FORWARDED_FOR の値が違うので「ip spoofing attack」が発生する。以下の様にコンフィグを false とすることで回避可能。ちな試したのはRails 3.2.3環境。

config.action_dispatch.ip_spoofing_check = false

configuration - Turning off ip spoofing check in Rails 3 application - Stack Overflow
※そもそもこの環境では、HTTP_X_FORWARDED_FOR の値を設定するのは、Rails へ IP を渡す目的だったのでHTTP_X_FORWARDED_FOR を削除すればコンフィグに脆弱になる項目を記述する必要はないので、Nginx を修正すべき。

追記

なお問題が発生した2

上記の通り「X-Forwarded-For」を削除して「Clinet-IP」だけにしてみたら、また Rails のログの取得する IP が「127.0.0.1」だけになった。なめんな。というわけで以下の4パターンで試行した。

1:
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Client-IP $remote_addr;
2:
proxy_set_header Client-IP $remote_addr;
3:
proxy_set_header Client-IP $proxy_add_x_forwarded_for;
4:
proxy_set_header X-Forwarded-For $remote_addr;

アクセス元の IP が取得できたのは1:の組み合わせのみ。しかしこれは spool なんとかになるしだめ、ということで「X-Forwarded-For」「Client-IP」に同じ値が設定されてればいい(中身にリクエスト元 IP が入ってる前提)んじゃね?という所から以下のようにしてみた。

proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Client-IP $remote_addr;

(IP がログで期待した通りに)とれた(よろこび)。
なおこの現象が発生するのは「NAT変換してないローカル IP を持つインターフェース同士で通信した場合」だと思われる。(社内の開発用サーバが NAT 変換されて 10.1.0.x -> NAT -> 10.10.x.x になってる環境では、NAT してるサーバの IP がとれてた)

よくわからんけど、これで spool なエラーも返って来ないし大丈夫だと思うけど、 Rails の IP 周りの処理(主にローカルネットワーク内での通信)が怪しい、とおもいました(小並感)。
ひょっとしなくても「ローカルネットワークでの通信によるウェブシステム?ローカルだしアクセス元とか関係ないだろゆっくりしね!むーしゃむーしゃ!!」みたいな思想とかあるんでしょうか?
Rails のバージョン上げて試行するのはつかれたので後日やります。


なお同僚が Google 検索でこの記事を発見し「おっあんじゃーん……お前の書いた記事じゃねえかぬわぁぁん!」みたいな雄叫びあげてた。わしゃ知らん。