从限流谈到伪造 IP(nginx remote_addr)
remote_addr
很多流量大的网站会限流,比如一秒 1000 次访问即视为非法,会阻止 10 分钟的访问。
通常简单的做法,就是通过 nginx 时,nginx 设置
proxy_set_header X-Real-IP $remote_addr;
nginx的 $remote_addr代表客户端的访问 ip,把它设到 http 请求的头部X-Real-IP;然后程序取出并存入数据库,统计访问次数。
remote_addr 基本上不能被伪造,因为是直接从 TCP 连接信息中获取的,也就是 netstat 的Foreign Address那栏。
你想想, 客户端A 与 B服务器建立 TCP 连接,是不是 B 肯定知道 A的公网地址是什么呢,除非客户端 A 是经过了一个代理服务器 Z, 那么就是 A -> Z -> B, 服务器 B 拿到的只能是 Z 的 ip 地址了,但这不意味就是伪造 ip,限流依然有效。
nginx 转发
上述应对外网访问,没有任何问题。假如公司内部需要测试,不停的访问服务器上的程序时,并且经过负载均衡或者 nginx 转发时,也就是 client -> nginx1 -> nginx2 -> server, remote_addr 就变成了nginx2 的内网地址了。
因此,需要在 nginx1处, e client 的 remote_addr, 再传给 nginx2,server 再取出。
示例:
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
$proxy_add_x_forwarded_for 把 $remote_addr 加到 X-Forwarded-For 头部后面;最后设在 my_ips
如果是需要做 ip 统计,地理信息获取,天气定位等,需要常用的另一个 http 头部,
X-Forwarded-For来做处理。通过名字就知道,X-Forwarded-For 是一个 HTTP 扩展头部。HTTP/1.1(RFC 2616)协议并没有对它的定义,它最开始是由 Squid 这个缓存代理软件引入,用来表示 HTTP 请求端真实 IP。如今它已经成为事实上的标准,被各大 HTTP 代理、负载均衡等转发服务广泛使用,并被写入 RFC 7239(Forwarded HTTP Extension)标准之中。[1]
然后my_ips 就代表了请求从 client 到 server 的完整ip路径, 只要由后往前推,直到 找到 外网的 ip,就证明这就是 client 的真正 ip。
```python
bb_real_ip = request.environ.get('my_ips')
bb_real_ip = bb_real_ip.replace(" ", "").split(',')
for ip in reversed(bb_real_ip):
if not is_private(ip):
return ip