文档章节

【整理】获取用户真实 ip 地址的 nginx 相关配置

摩云飞
 摩云飞
发布于 2014/07/29 15:25
字数 1266
阅读 15401
收藏 8

nginx 为实现反向代理的需求增加了一个 ngx_http_proxy_module 模块。其中 proxy_set_header 指令就是该模块需要读取的配置。

      HTTP header 中的 Host 含义为所请求的目的主机名。当 nginx 作为反向代理使用,而后端真实 web 服务器设置有类似 防盗链功能 ,或者根据 HTTP header 中的 Host 字段来进行 路由 过滤 功能的话,若作为反向代理的 nginx 不重写请求头中的 Host 字段,将会导致请求失败。

      HTTP header 中的  X_Forward_For  表示该条 http 请求是由谁发起的。如果反向代理服务器不重写该请求头的话,那么后端真实 web 服务器在处理时会认为所有的请求都来自反向代理服务器。如果后端 web 服务器有防攻击策略的话,那么反向代理服务器对应的 ip 地址就会被封掉。因此,在配置用作反向代理的 nginx 时,一般会增加以下两条配置修改 http 的请求头:
proxy_set_header Host $http_host;
proxy_set_header X-Forward-For $remote_addr;
      这里,$http_host 和 $remote_addr 都是 nginx 的导出变量,可以在配置文件中直接使用。如果 Host 没有出现在 HTTP header 中,则 $http_host 的值为空,而 $host 和 $http_host 同样表示请求头中的 Host 字段,但若 Host 字段不存在,则以实际处理的虚拟主机 server 的 server_name 替代。因此一般而言,会用 $host 代替 $http_host 变量(如下),从而避免 http 请求中丢失 Host 头部的情况下 Host 不被重写的失误。
proxy_set_header Host $host;
      服务器集群之间的通信,是可以信任的。我们要做的就是在离用户最近的前端代理上,强制设定 X-Forward-For 的值,后端所有机器不作任何设置,直接信任并使用前端机器传递过来的 X-Forward-For 值即可。
 
即在最前端的 Nginx 上设置:
location  ~  ^/static {
    proxy_pass  ....;
    proxy_set_header X-Forward-For $remote_addr ;
}
      记住,$remote_addr 是 nginx 的内置变量,代表了客户端真实(网络传输层)IP 。通过该设置,强行将 X-Forward-For 设置为客户端 ip ,使客户端无法通过本文所述方式“伪造 IP”。
      当 nginx 作为反向代理服务器时,X-Forward-For 可以用于把发送者 ip 、代理机器 ip 都记录下来(用逗号分隔)。

经过反向代理后,由于在客户端和 web 服务器之间增加了中间层,因此 web 服务器无法直接拿到客户端的 ip,在 web 服务器上通过 $remote_addr 变量拿到的将是反向代理服务器的 ip 地址
      当你使用了 nginx 反向代理后,在 web 端使用类似 request.getRemoteAddr() 的 API(本质上就是获取 $remote_addr),取得的实际上是 nginx 的地址,即 $remote_addr 变量中封装的是 nginx 的地址,当然是没法获得用户的真实 ip 的,然而 nginx 本身是可以获得用户的真实 ip 的,也就是说 nginx 使用 $remote_addr 变量可以获得用户的真实 ip ,如果我们想要在 web 端获得用户的真实 ip ,就必须在 nginx 这里作一个赋值操作,如下:
proxy_set_header  X-real-ip $remote_addr;
      其中这个 X-real-ip 是一个自定义的变量名,名字可以随意取,这样做完之后,用户的真实 ip 就被放在 X-real-ip 这个变量里了,然后,在 web 端可以通过类似如下 API 获取客户端 ip:
request.getAttribute("X-real-ip")

 X-real-ip 的用途是为了后端 web 服务器可以获取用户的真实 ip , 那么还要  X-Forwarded-For 干啥?
      追溯历史,这个 X-Forwarded-For 变量,是 squid 开发的,用于识别请求通过了哪些 HTTP 代理或负载平衡器,记录相应 IP 地址列表的非 rfc 标准,如果设置了 X-Forwarded-For ,那么每次经过 proxy 转发请求后都会有记录,格式就是
client1, proxy1, proxy2, ...
      以逗号隔开各个地址。由于是非 rfc 标准,所以默认是没有的,需要强制添加。在默认情况下经过 proxy 转发的请求,在后端 web 服务器看来远程地址都是 proxy 的 ip 地址。也就是说在默认情况下我们使用 request.getAttribute("X-Forwarded-For") 获取不到用户的 ip ,如果我们想要通过这个变量获得用户的 ip ,我们需要自己在 nginx 添加如下配置:
proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
      上述配置的意思是增加一个 $proxy_add_x_forwarded_for 到 X-Forwarded-For 里去,注意是增加,而不是覆盖。当然由于默认的 X-Forwarded-For 值是空的,所以我们总感觉 X-Forwarded-For 的值就等于 $proxy_add_x_forwarded_for 的值。

      实际上,当你通过搭建不同 ip 的两台 nginx 构成多级代理时,并且都使用了这段配置,那你会发现在 web 服务器端通过类似 request.getAttribute("X-Forwarded-For") 的 API 获得的将会是客户端 ip 和第一台 nginx 的 ip 。


试验:【以 http 方式通过 nginx 访问 cowboy】

浏览器侧抓包


cowboy 上抓包


© 著作权归作者所有

摩云飞
粉丝 377
博文 534
码字总数 952694
作品 0
徐汇
程序员
私信 提问
proxy_set_header的设置

先来看下proxysetheader的语法 允许重新定义或者添加发往后端服务器的请求头。可以包含文本、变量或者它们的组合。 当且仅当当前配置级别中没有定义指令时,会从上面的级别继承配置。 默认情...

M玺
2017/08/18
0
0
使用Nginx后如何在web应用中获取用户ip及原理解释

问题背景: 在实际应用中,我们可能需要获取用户的ip地址,比如做异地登陆的判断,或者统计ip访问次数等,通常情况下我们使用request.getRemoteAddr()就可以获取到客户端ip,但是当我们使用了...

点心木易
2013/04/23
288
3
nginx 获取真实ip

问题背景: 在实际应用中,我们可能需要获取用户的ip地址,比如做异地登陆的判断,或者统计ip访问次数等,通常情况下我们使用request.getRemoteAddr()就可以获取到客户端ip,但是当我们使用了...

技术小阿哥
2017/11/28
0
0
获取用户的真实ip

常见的坑有两个: 一、获取的是内网的ip地址。在nginx作为反向代理层的架构中,转发请求到php,java等应用容器上。结果php获取的是nginx代理服务器的ip,表现为一个内网的地址。php获取REMOT...

蜗牛奔跑
2016/03/08
235
0
Nginx 不受 CDN 服务影响获取访客真实 IP

获取和记录站点访客的真实 IP 对于站点日志的分析和安全策略的指定很有帮助,Nginx 默认的日志记录获取到的 IP 地址如果站点启用了 CDN 服务,那么这里的 IP 地址都是 CDN 服务器节点的 IP 地...

dragon_tech
2019/02/12
42
0

没有更多内容

加载失败,请刷新页面

加载更多

jsp web 大文件上传源代码

我们平时经常做的是上传文件,上传文件夹与上传文件类似,但也有一些不同之处,这次做了上传文件夹就记录下以备后用。 首先我们需要了解的是上传文件三要素: 1.表单提交方式:post (get方式提...

东方雨
23分钟前
53
0
读懂这一篇,集群节点不下线

作者 | 声东 阿里云售后技术专家 导读:排查完全陌生的问题、完全不熟悉的系统组件,是售后工程师的一大工作乐趣,当然也是挑战。今天借这篇文章,跟大家分析一例这样的问题。排查过程中,需...

阿里巴巴云原生
29分钟前
95
0
如何让scss变量能够当做js变量来使用

如何让scss变量能够当做js变量来使用 当前我们使用scss变量有两个痛点: 需要手动导入 无法与js建立联系或者很难,后续不能在此基础上做一些骚操作 为了解决这两个问题,我们以创建js文件以j...

念其蔚蓝
38分钟前
83
0
Java日期加减

public static String getDate(String dateGiven,Integer day) throws Exception{ SimpleDateFormat sdf= new SimpleDateFormat("yyyy-MM-dd"); Date date=sdf.parse(dateGiven);......

那个猩猩很亮
47分钟前
117
0
创龙TI TMS320C6748定点/浮点DSP C674xSD卡接口、拓展IO信号

TL138/1808/6748-EVM是广州创龙基于SOM-TL138/1808/6748核心板开发的一款开发板。由于SOM-TL138/1808/6748核心板管脚兼容,所以此三个核心板共用同一个底板。开发板采用核心板+底板的设计方式...

Tronlong创龙
47分钟前
81
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部