Nginx 与 X-Forwarded-For
壹
HTTP扩展头部 X-Forwarded-For,以及在nginx中使用http_x_forwarded_for变量来完成一些"特殊"功能,例如网站后台面向内部工作人员,希望只允许办公室网络IP访问。
X-Forwarded-For,它用来记录代理服务器的地址,每经过一个代理该字段会追加上一个记录。例如:6.6.6.6, 8.8.8.8。
贰
拿出生产环境的一个例子,客户端浏览网站发出一个请求,请求先经过阿里云SLB负载均衡器,然后进入Rancher内部的LB负载均衡器,经过两次负载均衡器转发后请求到达nginx服务器。
叁
X-Forwarded-For HTTP扩展头部
日志中的记录表示 client: 101.251.xxx.192 、proxy1: 100.97.xxx.187,不是说 X-Forwarded-For用来记录代理服务器的地址,每经过一个代理该字段会追加上一个记录,为什么client IP 会出现在这个字段中呢?
带着疑惑这里有必要专门讲一讲 X-Forwarded-For HTTP头部。X-Forwarded-For 是一个 HTTP扩展头部,HTTP/1.1(RFC 2616)协议并没有对它的定义,它最开始是由 Squid缓存代理软件引入,用来表示 HTTP请求端真实IP。最终成为事实上的标准被写入 RFC 7239(Forwarded HTTP Extension)标准之中。
X-Forwarded-For 标准格式
X-Forwarded-For: client, proxy1, proxy2
从标准格式可以看出,X-Forwarded-For头部信息可以有多个,中间使用逗号分隔,第一项为真实的客户端IP,剩下的就是经过的代理或负载均衡的IP地址,经过几个就会出现几个。
回到上面的示例,HTTP请求到达nginx服务器之前,经过了两个代理Proxy1、Proxy2,IP 分别为IP1、IP2,用户真实IP为 IP0,那么按照 XFF标准格式,nginx服务器最终的XFF变量如下:
X-Forwarded-For: IP0, IP1
Proxy2是直连服务器的,它会给 XFF追加IP1,表示它是在帮 Proxy1转发请求,IP2是在服务端通过 Remote Address 获得。Remote Address 也无法伪造,因为建立TCP连接需要三次握手,如果伪造了源IP,无法建立TCP连接,更不会有后面的 HTTP请求。
肆
nginx 中的 http_x_forwarded_for 变量用来表示 X-Forwarded-For ,下面用一个例子说明 nginx 如何使用 http_x_forwarded_for,例如借用这个变量限制网站后台访问。
1. 环境
browser -> haproxy -> nginx
目标判断 haproxy负载均衡传递的 http_x_forwarded_for变量,确定是否为办公室IP?是否允许访问网站后台?
2. 方法
a. 修改 nginx 虚拟主机配置文件,添加以下语句。
cat default.conf server { #... 其它配置项省略 location ^~ /admin/ { if ($http_x_forwarded_for !~ 'your_office_ip') { return 403; } #... 其它配置项省略 } }
b. 重新加载
nginx -t && nginx -s reload
c. 伪造XFF
需要特别说明的是XFF是可以伪造的,例如使用curl 发送一个带有"X-Forwarded-For:8.8.8.8"的头部信息。
curl -IL -H "X-Forwarded-For:8.8.8.8" https://www.test.com/static/09.png
假设你采用XFF对比IP方式来限制网站后台访问,如果对方知道你的网站在用这个策略限制后台访问,并且通过一些方法知道了你办公室的IP地址,那么这个策略也就失效了。如果你的网站"前后台"可以分离,那么可以为分离后的后台服务器添加防火墙规则,通过网络层限制来源IP地址达到同样目的。