Rails

LAN内でリバースプロキシを使用した場合の request.remote_ip

More than 3 years have passed since last update.

はまったのん…

環境

  • Rails 4.0.1
  • nginx + Unicorn

リバースプロキシを利用した場合のアクセス元アドレス

通常、リバースプロキシ (nginxなどのウェブサーバを含む; 以下単にプロキシ) を利用した場合、アクセス元はプロキシ側のIPアドレスとなるため実際のアドレスを知ることが出来ない。このため、プロキシ側ではリクエストヘッダ (Client-IP: など) にアクセス元のアドレスを含めることが多い。Webサーバはこの値を読んで本来のアドレスを知ることが出来る。

Railsでは request.env 中の情報を利用して、実際のリモートホストを取得することが出来る。ただし、request.remote_ip でヘッダの情報を処理した "正しい" リモートホストを参照することができるため、直接ヘッダの情報を参照するメリットはあまり無い。(この機能は ActionPack 中の ActionDispatch で提供されており、Client-IP: または X-Forwarded-For: に含まれるアドレスがリモートアドレスとして取り扱われる。)

問題点

LAN (プライベートIPアドレスを使用したネットワーク) 内にあるサーバにアクセスした場合には request.remote_ip がプロキシ側のアドレスとなってしまう。

※プロキシ側では Client-IP: または X-Forwarded-For: が設定されるものとする。

原因

ActionDispatch::RemoteIp::TRUSTED_PROXIES にマッチするアドレス (ループバックアドレスとプライベートアドレス) は、プロキシサーバと見なされ、Client-IP: や X-Forwarded-For: に含まれていても無視されるため。(ActionDispatch::RemoteIp::GetIp.filter_proxies で処理している。)

actionpack-4.0.1/lib/action_dispatch/middleware/remote_ip.rb
TRUSTED_PROXIES = %r{
  ^127\.0\.0\.1$                | # localhost IPv4
  ^::1$                         | # localhost IPv6
  ^fc00:                        | # private IPv6 range fc00
  ^10\.                         | # private IPv4 range 10.x.x.x
  ^172\.(1[6-9]|2[0-9]|3[0-1])\.| # private IPv4 range 172.16.0.0 .. 31.255.255
  ^192\.168\.                     # private IPv4 range 192.168.x.x
}x

対策

プロキシのみにマッチする正規表現を Rails.configuration.action_dispatch.trusted_proxies に設定する。

config/environments/production.rb
Hoge::Application.configure do
  ...
  config.action_dispatch.trusted_proxies = /^127\.|^::1$/
end

ここでは、ループバックアドレスのみをプロキシサーバとして扱うよう設定した。

まとめ

  • ドキュメントをサガしたけど直接書かれているものが見つからず、ソースコードを読むことに。オープンソースはありがたいけど、初心者には辛い。
  • デフォルトで Client-IP: や X-Forwarded-For: を処理したり、プライベートアドレスをプロキシ扱いにするのは、あまり筋が良くないと思う。
  • こまちゃん可愛い