获取用户的真实 IP,对于安全业务来说非常重要。阿里云场景下一个Http 请求一般为:
用户IP --> Ddos 高防 IP ->SLB IP
对于WEB服务器来说,主要是通过两种方式获取 IP
与服务器建立TCP连接的地址 Remote Address通过 Http Header 的 X-Forwarded-For 字段对应的 PHP 变量如下
$_SERVER['REMOTE_ADDR'] // 与服务建立TCP连接的IP $_SERVER['HTTP_X_FORWARDED_FOR'] // 获取 Http 请求头 X-Forwarded-For数据X-Forwarded-For: client, proxy1, proxy2
如果一个 HTTP 请求到达服务器之前,经过了三个代理 Proxy1、Proxy2、Proxy3,IP 分别为 IP1、IP2、IP3,用户真实 IP 为 IP0,服务端最终会收到以下信息:
X-Forwarded-For: IP0, IP1, IP2
Proxy3 直连服务器,它会给 XFF 追加 IP2,表示它是在帮 Proxy2 转发请求。列表中并没有 IP3,IP3 可以在服务端通过 REMOTE_ADDR 字段获得。
如果用户篡改 X-Forwarded-For
curl http://a.b.com/ -H 'X-Forwarded-For: IP100' ,服务端会受到如下信息; X-Forwarded-For: IP100, IP0, IP1, IP2
我们怎么通过这两个字段获取用户真实 IP 呢?
如果 HTTP 请求没有经过七层代理,直接读取 REMOTE_ADDR 字段最好如果 HTTP 请求经过七层代理, 我们只能从 X-Forwarded-For 获取,但是我们必须过滤用户伪造数据,获取真实的用户 IP如上面例子 IP1, IP2是我们自己配置的 IP,可信任的IP,过滤掉可信任的代理IP,最后一个不可信任的IP就是用户IP。要解决的问题如下
nginx的访问日志,记录用户真实ip,现在记录的是Remote Address。php获取用户真实IP,如果我们获取X-Forwarded-For第一个IP。容易被用户篡改。调研过程中,发现ngx_http_realip_module 满足我们需求, 当获取了用户真实IP,会赋值给 nginx变量 $remote_addr 变量,那么 PHP的 $_SERVER['REMOTE_ADDR'] 也变成了用户真实IP。
与web服务器建议TCP连接的IP 存储在变量 $realip_remote_addr 中。
set_real_ip_from 192.168.1.0/24; real_ip_header X-Forwarded-For; real_ip_recursive on; set_ip_from 设置信任 IP,就是我们自己的代理IP,可以设置多个real_ip_header 设置请求头字段,表示从X-Forwarded-For字段获取用户 IPreal_ip_recursive off:如果remote address 能够匹配set_real_ip_from 的ip,用户 X-Forwarded-For最后一个 IP 作为用户IP。on: 如果remote address 能够匹配set_real_ip_from 的ip,用户 X-Forwarded-For最后一个不可信任 IP 作为用户IP。
我们的配置如下,注意还没有上线
nginx 配置如下
#slb IP set_real_ip_from 100.64.0.0/10; # ddos高防iP的回源IP set_real_ip_from 180.97.165.0/24; set_real_ip_from 180.97.166.0/24; set_real_ip_from 180.97.88.0/24; set_real_ip_from 116.211.163.0/24; set_real_ip_from 116.211.164.0/24; set_real_ip_from 116.211.165.0/24; set_real_ip_from 218.60.116.0/24; set_real_ip_from 218.60.117.0/24; set_real_ip_from 218.60.120.0/24; set_real_ip_from 218.11.4.0/24; set_real_ip_from 121.29.52.0/24; set_real_ip_from 121.29.53.0/24; set_real_ip_from 120.55.146.0/24; set_real_ip_from 120.55.147.0/24; set_real_ip_from 120.55.177.0/24; set_real_ip_from 120.27.173.0/24; set_real_ip_from 118.178.15.0/24; set_real_ip_from 118.178.177.0/24; set_real_ip_from 118.178.202.0/24; set_real_ip_from 118.178.203.0/24; set_real_ip_from 118.178.204.0/24; set_real_ip_from 118.178.221.0/24; set_real_ip_from 118.178.222.0/24; set_real_ip_from 118.178.223.0/24; set_real_ip_from 118.178.244.0/24; real_ip_header X-Forwarded-For; real_ip_recursive on;PHP 获取用户IP$_SEVER['REMOTE_ADDR']
https://imququ.com/post/x-forwarded-for-header-in-http.html
http://nginx.org/en/docs/http/ngx_http_realip_module.html
http://baike.baidu.com/item/IANA保留地址?fr=aladdin
