跳转至

Nginx 与 X-Forwarded-For


2016-01-21 by dongnan

今天的这篇文章发布于2016年01月,是介绍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服务器。

拓扑环境

client(浏览器) -> proxy1(SLB) -> proxy2(Haproxy) -> server(Nginx) 

Nginx

日志内容

10.42.xxx.115 [01/Aug/2019:10:47:01 +0800] "GET /static/09.png HTTP/1.1" 200 23029 "https://demo.com/dashboard" "Mozilla/5.0 " 
101.251.xxx.192, 100.97.xxx.187

日志格式

# access
log_format  access  '$remote_addr [$time_local] "$request" '
                  '$status $body_bytes_sent "$http_referer" '
                  '"$http_user_agent" $http_x_forwarded_for';

IP关系

proxy2: 10.42.xxx.115 
proxy1: 100.97.xxx.187
client: 101.251.xxx.192

X-Forwarded-For

日志中的记录表示 client: 101.251.133.192 、proxy1: 100.97.200.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: 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请求。

http_x_forwarded_for 变量

聊完 X-Forwarded-For HTTP扩展头部,下面用一个例子说明 nginx 如何使用 http_x_forwarded_for,变量限制网站后台访问

环境

browser -> haproxy -> nginx

目标

判断 haproxy负载均衡传递的 http_x_forwarded_for变量,确定是否公室网络IP是否允许访问网站后台。

方法

修改 nginx 虚拟主机配置文件,添加以下语句。

server  
{    
  #... 其它配置项省略

    location ^~ /admin/ {

      if ($http_x_forwarded_for !~ 'your_office_ip') {
         return 403;
      } 

      #... 其它配置项省略    
    }

}

重新加载

nginx -t && nginx -s reload

伪造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地址达到同样目的。

参考文章

回到页面顶部