RailsでのIPの取得について


Ruby on RailsでリクエストのIPを取得するのは次の方法があります。

# 元のIPアドレス
request.remote_ip
# X-Forwarded-For の値を取得する
request.env['HTTP_X_FORWARDED_FOR']

🍄 remote_ipの実装について

Rails 5.1のrequest.remote_ipの元となっている処理は「rails/remote_ip.rb 」にあります。

HTTPヘッダのX_FORWARDED_FORCLIENT_IPREMOTE_ADDRから最初に見つかった有効なIPを取得しているようです。

def calculate_ip
# Set by the Rack web server, this is a single value.
remote_addr = ips_from('REMOTE_ADDR').last
# Could be a CSV list and/or repeated headers that were concatenated.
client_ips = ips_from('HTTP_CLIENT_IP').reverse
forwarded_ips = ips_from('HTTP_X_FORWARDED_FOR').reverse
# +Client-Ip+ and +X-Forwarded-For+ should not, generally, both be set.
# If they are both set, it means that this request passed through two
# proxies with incompatible IP header conventions, and there is no way
# for us to determine which header is the right one after the fact.
# Since we have no idea, we give up and explode.
should_check_ip = @check_ip && client_ips.last
if should_check_ip && !forwarded_ips.include?(client_ips.last)
# 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
# We assume these things about the IP headers:
#
# - X-Forwarded-For will be a list of IPs, one per proxy, or blank
# - Client-Ip is propagated from the outermost proxy, or is blank
# - REMOTE_ADDR will be the IP that made the request to Rack
ips = [forwarded_ips, client_ips, remote_addr].flatten.compact
# If every single IP option is in the trusted list, just return REMOTE_ADDR
filter_proxies(ips).first || remote_addr
end

🍣 信頼するプロキシの設定

ActionDispatch::RemoteIp::TRUSTED_PROXIESにマッチするアドレスはプロキシサーバとみなされて、Client-IPX-Forwarded-Forから除外されます。rails/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 .. 172.31.255.255
^192\.168\. # private IPv4 range 192.168.x.x
}x

ループバックアドレス(自身のIP)のみ取り除き、そのほかは表示するようにするためには
config/environments/production.rbに次のように設定します。

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

🚜 参考リンク

📚 おすすめの書籍