request.ip
request.ip
是Rack::Request
开箱即用提供的基本ip检测。它的当前定义可以在https://github.com/rack/rack/blob/master/lib/rack/request.rb中找到。
遵循的算法是首先检查REMOTE_ADDR
标头中是否存在任何不受信任的IP地址,如果找到了该IP地址,它将选择列出的第一个。在这种情况下,“受信任的” IP地址是来自保留的专用子网范围的IP地址,但请注意,它通过regex进行匹配,这可能不是最佳方法。如果没有不信任的内容,REMOTE_ADDR
那么它将查看HTTP_X_FORWARDED_FOR
标题,并选择列出的最后一个不信任的内容。如果这些都不显示任何内容,那么它会退回到原始REMOTE_ADDR
值(可能是127.0.0.1)。
request.remote_ip
request.remote_ip
是的增强IP检测ActionDispatch::Request
(由继承Rack::Request
)。这是问题中显示的代码。如您所见,request.ip
除非action_dispatch.remote_ip
在上设置,否则它会回落到@env
。这由RemoteIp
中间件完成,该中间件包含在默认的Rails堆栈中。您可以在https://github.com/rails/rails/blob/4-2-stable/actionpack/lib/action_dispatch/middleware/remote_ip.rb上查看其源代码。
该RemoteIp
如果启用中间件提供这些附加功能:
- 提供可选但默认的IP欺骗检测。
- 允许过滤配置代理地址,而不是仅依赖默认值。
- 使用
IPAddr
该类实际正确地测试IP范围,而不是依赖于脆弱的正则表达式。
- 用途
HTTP_CLIENT_IP
作为潜在的IP地址的来源。
该算法类似于request.ip
但略有不同。它使用HTTP_X_FORWARDED_FOR
从最后到第一,然后HTTP_CLIENT_IP
从最后到第一,然后最后使用的最后一个条目REMOTE_ADDR
。它将所有这些放入列表并过滤代理,并选择剩下的第一个。
IP欺骗检测
所提供的IP欺骗检测RemoteIp
是不是特别强大,它的作用是抛出一个异常,如果最后HTTP_CLIENT_IP
不是HTTP_X_FORWARDED_FOR
。这不一定是攻击的征兆,但可能是配置错误或使用不同约定混合代理的征兆,这些约定没有产生连贯的结果。
使用哪个
在代理都位于本地或专用子网中的简单设置中,您可能可以摆脱request.ip
,但request.remote_ip
通常应将其视为首选。如果将代理与公共Internet路由(例如许多CDN)一起使用,则RemoteIp
可以配置为为您提供开箱即用的正确客户端IP,而request.ip
只有在您可以REMOTE_ADDR
正确设置上游代理的情况下才是正确的。
安全配置
现在来解决蒂姆·库尔特关于欺骗的评论。他绝对是对的,应该引起您的关注,但是他错了,如果默认情况下您落后于nginx或haproxy,那么您可能会被欺骗。 RemoteIp
通过选择链中的最后一个IP来防止欺骗。在X -转发,对于规范规定,各代理追加请求方的IP到链的末端。通过过滤掉列入白名单的代理,可以确保最后一个条目是您的第一个列入白名单的代理编写的客户端IP。当然还有一点需要说明,这是你必须确实运行一个代理,一直套/追加X-Forwarded-For
,所以蒂姆的建议实际上应该是相反的:只有使用request.remote_ip
时您正在运行的代理。
如何配置公共IP代理
一切都很好,但是ActionDispatch::RemoteIp
已经在默认的中间件堆栈中了。如何重新配置它以添加我的代理CIDR ?!
将此添加到您的application.rb
:
check_spoofing = true
proxies = ["23.235.32.0/20", "203.57.145.0/24"]
proxies += ActionDispatch::RemoteIp::TRUSTED_PROXIES
config.middleware.swap ActionDispatch::RemoteIp,
ActionDispatch::RemoteIp,
true,
proxies
request.remote_ip
通过HTTP_X_FORWARDED_FOR链进行查找,但如果在Nginx或haproxy后面有Rails,它仍然可以被欺骗。在nginx中,使用proxy_set_header X-Forwarded-For $remote_addr;
代替proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
。在后一种情况下,curl -H "X-Forwarded-For: 6.66.6.66" http://example.com
将产生request.remote_ip
6.66.6.66,这将欺骗您在Rails中使用的所有IP检查。