defer calculating the remote IP until requested

This commit is contained in:
Andre Arko
2011-11-12 00:45:31 -10:00
parent 9432163c60
commit 317f4e2236

View File

@@ -13,6 +13,8 @@ module ActionDispatch
)\. )\.
}x }x
attr_reader :check_ip_spoofing, :trusted_proxies
def initialize(app, check_ip_spoofing = true, custom_proxies = nil) def initialize(app, check_ip_spoofing = true, custom_proxies = nil)
@app = app @app = app
@check_ip_spoofing = check_ip_spoofing @check_ip_spoofing = check_ip_spoofing
@@ -24,34 +26,44 @@ module ActionDispatch
end end
end end
def call(env)
env["action_dispatch.remote_ip"] = GetIp.new(env, self)
@app.call(env)
end
class GetIp
def initialize(env, middleware)
@env, @middleware = env, middleware
end
# Determines originating IP address. REMOTE_ADDR is the standard # Determines originating IP address. REMOTE_ADDR is the standard
# but will be wrong if the user is behind a proxy. Proxies will set # but will be wrong if the user is behind a proxy. Proxies will set
# HTTP_CLIENT_IP and/or HTTP_X_FORWARDED_FOR, so we prioritize those. # HTTP_CLIENT_IP and/or HTTP_X_FORWARDED_FOR, so we prioritize those.
# HTTP_X_FORWARDED_FOR may be a comma-delimited list in the case of # HTTP_X_FORWARDED_FOR may be a comma-delimited list in the case of
# multiple chained proxies. The last address which is not a known proxy # multiple chained proxies. The last address which is not a known proxy
# will be the originating IP. # will be the originating IP.
def call(env) def to_s
client_ip = env['HTTP_CLIENT_IP'] client_ip = @env['HTTP_CLIENT_IP']
forwarded_ips = ips_from(env, 'HTTP_X_FORWARDED_FOR') forwarded_ips = ips_from('HTTP_X_FORWARDED_FOR')
remote_addrs = ips_from(env, 'REMOTE_ADDR') remote_addrs = ips_from('REMOTE_ADDR')
if client_ip && @check_ip_spoofing && !forwarded_ips.include?(client_ip) check_ip = client_ip && @middleware.check_ip_spoofing
if check_ip && !forwarded_ips.include?(client_ip)
# We don't know which came from the proxy, and which from the user # We don't know which came from the proxy, and which from the user
raise IpSpoofAttackError, "IP spoofing attack?!" \ raise IpSpoofAttackError, "IP spoofing attack?!" \
"HTTP_CLIENT_IP=#{env['HTTP_CLIENT_IP'].inspect}" \ "HTTP_CLIENT_IP=#{env['HTTP_CLIENT_IP'].inspect}" \
"HTTP_X_FORWARDED_FOR=#{env['HTTP_X_FORWARDED_FOR'].inspect}" "HTTP_X_FORWARDED_FOR=#{env['HTTP_X_FORWARDED_FOR'].inspect}"
end end
remote_ip = client_ip || forwarded_ips.last || remote_addrs.last client_ip || forwarded_ips.last || remote_addrs.last
env["action_dispatch.remote_ip"] = remote_ip
@app.call(env)
end end
protected protected
def ips_from(env, header) def ips_from(header)
ips = env[header] ? env[header].strip.split(/[,\s]+/) : [] ips = @env[header] ? @env[header].strip.split(/[,\s]+/) : []
ips.reject{|ip| ip =~ @trusted_proxies } ips.reject{|ip| ip =~ @middleware.trusted_proxies }
end
end end
end end