经过代理如何获取真实IP 及 laravel 中配置可信代理的原理
客户端直接访问后端服务器时,$_SERVER['REMOTE_ADDR']
ji真实客户端 IP:
remote_addr 是无法伪造的:因为建立 TCP 连接需要三次握手,如果伪造了源 IP,无法建立 TCP 连接。
可如果经过代理
$_SERVER['REMOTE_ADDR']
是上一级代理的 IP。
真实 IP 通常在 headers
中的 X-Forwarded-For
和 X-Real-Ip
来获取:
X-Forwarded-For 是一个 HTTP 扩展头部。HTTP/1.1(RFC 2616)协议并没有对它的定义,它最开始是由 Squid 这个缓存代理软件引入,用来表示 HTTP 请求端真实 IP。如今它已经成为事实上的标准,被各大 HTTP 代理、负载均衡等转发服务广泛使用,并被写入 RFC 7239(Forwarded HTTP Extension)标准之中。
X-Real-IP,这又是一个自定义头部字段。X-Real-IP 通常被 HTTP 代理用来表示与它产生 TCP 连接的设备 IP,这个设备可能是其他代理,也可能是真正的请求端。需要注意的是,X-Real-IP 目前并不属于任何标准,代理和 Web 应用之间可以约定用任何自定义头来传递这个信息。
我们只讨论 X-Forwarded-For
。图2 中的 proxy
代理到 server
需如下配置
location / {
proxy_pass http://server;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
同理,如果再有多个代理:
通过观察,请求头 X-Forwarded-For 的组成是:client,proxy1,proxy2..
第一个 ip 就是客户端 ip,PHP 中获取: $_SERVER['HTTP_X_FORWARDED_FOR'][0]
。
X-Forwarded-For 是可以伪造的,当 client
发送这样的请求时:
curl http://xx/ -H 'X-Forwarded-For: 123.123.123.123'
proxy1
再转发给 proxy2
location / {
proxy_pass http://proxy2;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
最终:
甚至是不法字符串:
curl http://xx/ -H 'X-Forwarded-For: select 1 = 1'
所以取第一个不一定准确,如果没有检查 ip 的格式,还有安全隐患。可以用以下方法检验 ip:
$long = sprintf("%u", ip2long($ip));
$ip = $long ? $ip : '0.0.0.0';
我们可以这样配置面向客户端的 proxy1
的代理转发,把真实客户端 ip $remote_addr
直接传给 `X-Forwarded-For:
location / {
proxy_pass http://proxy2;
#proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-For $remote_addr;
}
这样就保证了第一个是真实地址。
假设第一个有可能伪造,便引入了可信代理的概念。假设中间代理是可信任的,即不可能伪造 X-Forwarded-For
。如果 server
端获取的 X-Forwarded-For
头是:
"http_x_forwarded_for": "select 1 = 1,1.1.1,2.2.2.2,3.3.3.3,4.4.4.4"
配置可信代理:
protected $proxies = [
'4.4.4.4',
'3.3.3.3',
'2.2.2.2',
];
由后向前依次排除,直到 1.1.1.1
不在可信列表中,就认为是真实客户端 IP。
我们还可以通过 nginx 配置 set_real_ip_from
使 remote_addr
为客户端真实地址,此配置项依赖 nginx 扩展模块 http_realip_module
。
具体方法是,先 nginx -V
检查 nginx 是否包含模块 http_realip_module
,然后在 nginx.conf
的 http 上下文添加:
# 可以添加多条指令,支持 IP、IP段
set_real_ip_from 172.10.0.1;
set_real_ip_from 10.0.0.0/16;
real_ip_header X-Forwarded-For;
经此设置后,nginx 的变量 $remote_addr
将为客户端 IP,它的原理也是上文中的原理。
参考:www.runoob.com/w3cnote/http-x-forw...
本作品采用《CC 协议》,转载必须注明作者和本文链接
好文章