文章开始前,我先讲一个开发中的小故事,能够加深一下你们对这个字段的理解。html
前段时间要作一个和风控相关的需求,须要拿到用户的 IP,开发后灰度了一小部分用户,测试发现后台日志里灰度的用户 IP 全是异常的,哪有这么巧的事情。随后测试发过来几个异常 IP:前端
10.148.2.122
10.135.2.38
10.149.12.33
...
复制代码
一看 IP 特征我就明白了,这几个 IP 都是 10 开头的,属于 A 类 IP 的私有 IP 范围(10.0.0.0-10.255.255.255),后端拿到的确定是代理服务器的 IP,而不是用户的真实 IP。webpack
如今有些规模的网站基本都不是单点 Server 了,为了应对更高的流量和更灵活的架构,应用服务通常都是隐藏在代理服务器以后的,好比说 Nginx。nginx
加入接入层后,咱们就能比较容易的实现多台服务器的负载均衡和服务升级,固然还有其余的好处,好比说更好的内容缓存和安全防御,不过这些不是本文的重点就不展开了。web
网站加入代理服务器后,除了上面的几个优势,同时引入了一些新的问题。好比说以前的单点 Server,服务器是能够直接拿到用户的 IP 的,加入代理层后,如上图所示,(应用)原始服务器拿到的是代理服务器的 IP,我前面讲的故事的问题就出在这里。后端
Web 开发这么成熟的领域,确定是有现成的解决办法的,那就是 X-Forwarded-For 请求头。浏览器
X-Forwarded-For
是一个事实标准,虽然没有写入 HTTP RFC 规范里,从普及程度上看其实能够算 HTTP 规范了。缓存
这个标准是这样定义的,每次代理服务器转发请求到下一个服务器时,要把代理服务器的 IP 写入 X-Forwarded-For
中,这样在最末端的应用服务收到请求时,就会获得一个 IP 列表:安全
X-Forwarded-For: client, proxy1, proxy2
复制代码
由于 IP 是一个一个依次 push 进去的,那么第一个 IP 就是用户的真实 IP,取来用就行了。性能优化
可是,事实有这么简单吗?
从安全的角度上考虑,整个系统最不安全的就是人,用户端都是最好攻破最好伪造的。有些用户就开始钻协议的漏洞:X-Forwarded-For
是代理服务器添加的,若是我一开始请求的 Header 头里就加了 X-Forwarded-For
,不就骗过服务器了吗?
1. 首先从客户端发出请求,带有 X-Forwarded-For
请求头,里面写一个伪造的 IP:
X-Forwarded-For: fakeIP
复制代码
2. 服务端第一层代理服务收到请求,发现已经有 X-Forwarded-For
,误把这个请求当成代理服务器,因而向这个字段追加了客户端的真实 IP:
X-Forwarded-For: fakeIP, client
复制代码
3. 通过几层代理后,最终的服务器拿到的 Header 是这样的:
X-Forwarded-For: fakeIP, client, proxy1, proxy2
复制代码
要是按照取 X-Forwarded-For
第一个 IP 的思路,你就着了攻击者的道了,你拿到的是 fakeIP,而不是 client IP。
服务端如何破招?上面三个步骤:
第二步的破招我拿 Nginx 服务器举例。
咱们在最外层的 Nginx 上,对 X-Forwarded-For
的配置以下:
proxy_set_header X-Forwarded-For $remote_addr;
复制代码
什么意思呢?就是最外层代理服务器不信任客户端的 X-Forwarded-For
输入,直接覆盖,而不是追加。
非最外层的 Nginx 服务器,咱们配置:
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
复制代码
$proxy_add_x_forwarded_for
就是追加 IP 的意思。经过这招,就能够破招用户端的伪造办法。
第三步的破招思路也很容易,正常思路咱们是取X-Forwarded-For
最左侧的 IP,此次咱们反其道而行之,从右边数,减去代理服务器的数目,那么剩下的 IP 里,最右边的就是真实 IP。
X-Forwarded-For: fakeIP, client, proxy1, proxy2
复制代码
好比说咱们已知代理服务有两层,从右向左数,把 proxy1
和 proxy2
去掉,剩下的 IP 列表最右边的就是真实 IP。
相关思路和代码实现可参考 Egg.js 前置代理模式。
经过 X-Forwarded-For
获取用户真实 IP 时,最好不要取第一个 IP,以防止用户伪造 IP。
本文选自个人长文HTTP 规范中的那些暗坑,想要了解更多可点击原文查看。
更多推荐:
最后推荐一下个人我的公众号:「卤蛋实验室」,平时会分享一些前端技术和数据分析的内容,你们感兴趣的话能够关注一波: