由于开发时,要同时运行多个项目,并且都在 80 端口。所以项目在 3000 端口启动,然后通过 Nginx 做反向代理。客户端请求 nginx 即可。
但是在 controller 里调用 request.remote_ip
得到的 IP 是 127.0.0.1,而不是客户端 IP。于是我在 Nginx 里设置了 HTTP_CLIENT_IP 头为客户端 IP 后,就会抛异常 IpSpoofAttackError
,报错:IP spoofing attack。
这只是在内网出的问题。我使用同样的 Nginx 配置,并在公网里的项目里,调用 request.remote_ip
能正常返回客户端 IP。
细节如下:
Nginx 这样配置的
server {
listen 80;
server_name abc.com;
location / {
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_buffering on;
if (!-f $request_filename) {
proxy_pass http://127.0.0.1:3000;
break;
}
}
}
后来找到这个问题 http://stackoverflow.com/questions/10710486/wrong-ip-address-with-nginx-unicorn-rails ,添加了一行命令
proxy_set_header CLIENT_IP $remote_addr;
接下来就报错了。抛出 IpSpoofAttackError 异常,提示 IP spoofing attack?,给打印出了 HTTP_CLIENT_IP 和 HTTP_X_FORWARDED_FOR。对应 rails 源码中的 https://github.com/rails/rails/blob/3-2-stable/actionpack/lib/action_dispatch/middleware/remote_ip.rb 文件。
读了一下源码,发现是 rails 会根据 HTTP_CLIENT_IP、HTTP_X_FORWARDED_FOR 或者 REMOTE_ADDR 来得到 remote_ip。
第一种情况 Nginx 没有设置 CLIENT_IP 时,rails 拿到的 HTTP_CLIENT_IP 为nil
,就从 HTTP_X_FORWARDED_FOR 里找,但找之前,会处理一下,去掉 HTTP_X_FORWARDED_FOR 里的内网 IP(客户端的 IP 是 192.168.x.x),所以在 HTTP_X_FORWARDED_FOR 里还是找不到。只能在 REMOTE_ADDR 找了。而 REMOTE_ADDR 返回是 127.0.0.1。
第二种情况 Nginx 设置了 CLIENT_IP,rails 拿到的 HTTP_CLIENT_IP 是 192.168.x.x。而这个 IP,并不在处理后的 HTTP_X_FORWARDED_FOR 里,所以报错了。
没找到有效的解决办法,我只能在 development.rb 里配置
config.action_dispatch.ip_spoofing_check = false
因为不想在生产环境里关闭这个检查,所以不想在 production.rb 里增加这个配置。但是,在内网用 production.rb 测试时,又会遇到错误。
请问大家有遇到这个情况吗?该如何解决呢?