Rails の request.remote_ip には何の値が入っているのか

表題の通り Rails 3.2.X 系の request.remote_ip に入っている値について調べました。

最初に結論

リクエストヘッダを読み HTTP_CLIENT_IP, HTTP_X_FORWARDED_FOR, REMOTE_ADDR の順にセットされていた値を取得してきます。

ソースコード

http://api.rubyonrails.org/classes/ActionDispatch/RemoteIp/GetIp.html

上記 API にも記載されていますが calculate_ip が該当のメソッドです。

# File actionpack/lib/action_dispatch/middleware/remote_ip.rb, line 47
def calculate_ip
  client_ip     = @env['HTTP_CLIENT_IP']
  forwarded_ips = ips_from('HTTP_X_FORWARDED_FOR')
  remote_addrs  = ips_from('REMOTE_ADDR')

  check_ip = client_ip && @middleware.check_ip
  if check_ip && !forwarded_ips.include?(client_ip)
    # We don't know which came from the proxy, and which from the user
    raise IpSpoofAttackError, "IP spoofing attack?!"              "HTTP_CLIENT_IP=#{@env['HTTP_CLIENT_IP'].inspect}"              "HTTP_X_FORWARDED_FOR=#{@env['HTTP_X_FORWARDED_FOR'].inspect}"
  end

  not_proxy = client_ip || forwarded_ips.last || remote_addrs.first

  # Return first REMOTE_ADDR if there are no other options
  not_proxy || ips_from('REMOTE_ADDR', :allow_proxies).first
end

そんなわけで、いくら HTTP_X_FORWARDED_FOR の値をセットしてあげても HTTP_CLIENT_IP の値が書き変わっていたら正しいアドレスは取得できず、ログにはすべてのリクエストが 127.0.0.1 からとして記録されたりします。

ウェブサーバ側の設定

ここでは Nginx の場合の追加ヘッダー設定を記載します(Apache の場合については調査していませんが、大体同じような方法で設定可能だと思います)。コンフィグファイルを開いて、次のような設定を行います。

server {
  # 略
  proxy_set_header Client-IP $remote_addr; 
}

もちろん HTTP_X_FORWARDED_FOR 等の設定もきちんと行わないといけませんが Rails の場合はこれが最優先のようなので、うまくアドレスがログに表示されていない場合はこのあたりの設定を見直すといいと思います。

ActionDispatch::RemoteIp::IpSpoofAttackError への対処

上の設定で HTTP_CLIENT_IP と HTTP_X_FORWARDED_FOR にプライベート IP の値や、異なる値を設定した場合などに ActionDispatch::RemoteIp::IpSpoofAttackError が起きる事があります。
どうしてもそうした設定を行いたい場合は Rails 側のコンフィグでチェックを行わないように設定する事ができます。
config/application.rb または任意の環境向けのコンフィグファイルで次の設定を行ってください。

Hoge::Application.configure do
  config.action_dispatch.ip_spoofing_check = false
end