反向代理与 Real-IP 和 X-Forwarded-For

开篇语:开涛新作《亿级流量网站架构核心技术》出版计划公布以来,博文视点遭受到一波又一波读者询问面世时间的DDos攻击。面对亿级流量的热情,感激之余,我们也很庆幸——这部作品质量的确过硬,不会辜负拥趸厚望,更有开涛的高度负责和体贴周到加持,让她绝对物超所值、长久流芳。下面,看一篇来自这位技术暖男的售前支持。
——本书策划编辑 侠少

  本文作者张开涛。为保障《亿级流量网站架构核心技术》一书内容的连续性,有些需要读者了解的内容,或者书的补充和引申内容,会通过二维码嵌入的方式引导读者阅读学习。大家可以关注作者公众号“开涛的博客”,并从菜单栏“我的新书”中查阅相关内容。

  本文是「4.4 接入层限流」节中的「按照IP限制并发连接数配置示例」部分需要了解的内容。
  当我们访问互联网上的服务时,大多数时,客户端并不是直接访问到服务端的,而是客户端首先请求到反向代理,反向代理再转发到服务端实现服务访问,通过反向代理实现路由/负载均衡等策略。这样一来在服务端拿到的客户端IP将是反向代理IP,而不是真实客户端IP,因此需要一种办法来获取到真实客户端IP。
  如下图所示,客户端通过Nginx Proxy1 和 Nginx Proxy2 两层反向代理才访问到具体服务Nginx Backend(或如Tomcat服务)。那Nginx Backend如何才能拿到真实客户端IP呢?

  接下来我们来看看如何才能获取到客户端真实IP。

场景1

  场景1是很简单的场景,Nginx Proxy直接把请求往后转发,没有做任何处理。

Nginx Proxy
192.168.107.107 nginx.conf
location /test {
    proxy_pass http://192.168.107.112:8080;
}
192.168.107.112 nginx.conf
location /test {
    proxy_pass http://192.168.107.114:8080;
}
Nginx Proxy就是简单的把请求往后转发。
Nginx Backend
192.168.107.114 nginx.conf
location /test {
    default_type text/html;
    charset gbk;
    echo "$remote_addr || $http_x_forwarded_for";
}

  Nginx Backend输出客户端IP($remote_addr)和X-Forwarded-For请求头($http_x_forwarded_for),当访问服务时输出结果如下所示:

192.168.107.112 ||

分析

1.$remote_addr代表客户端IP,当前配置的输出结果为最后一个代理服务器的IP,并不是真实客户端IP;
2.在没有特殊配置情况下,X-Forwarded-For请求头不会自动添加到请求头中,即Nginx Backend的$http_x_forwarded_for输出为空。

场景2

  场景2通过添加X-Real-IP和X-Forwarded-For捕获客户端真实IP。

Nginx Proxy
192.168.107.107 nginx.conf
location /test {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://192.168.107.112:8080;
}
192.168.107.112 nginx.conf
location /test {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://192.168.107.114:8080;
}
Nginx Backend
192.168.107.114 nginx.conf
location /test {
    default_type text/html;
    charset gbk;
    echo "$remote_addr ||$http_x_real_ip  ||$http_x_forwarded_for";
}

  当访问服务时,输出结果为:

192.168.107.112 || 192.168.162.16 || 192.168.162.16, 192.168.107.107

分析

1.在离用户最近的反向代理NginxProxy 1,通过“proxy_set_header X-Real-IP $remote_addr”把真实客户端IP写入到请求头X-Real-IP,在NginxBackend输出$http_x_real_ip获取到了真实客户端IP;而Nginx Backend的“$remote_addr”输出为最后一个反向代理的IP;
2.“proxy_set_headerX-Forwarded-For $proxy_add_x_forwarded_for”的是把请求头中的X-Forwarded-For与$remote_addr用逗号合起来,如果请求头中没有X-Forwarded-For则$proxy_add_x_forwarded_for为$remote_addr。
  X-Forwarded-For代表了客户端IP,反向代理如Nginx通过$proxy_add_x_forwarded_for添加此项,X-Forwarded-For的格式为X-Forwarded-For:real client ip, proxy ip 1, proxy ip N,每经过一个反向代理就在请求头X-Forwarded-For后追加反向代理IP。
  到此我们可以使用请求头X-Real-IP和X-Forwarded-For来获取客户端IP及客户端到服务端经过的反向代理IP了。这种方式还是很麻烦,$remote_addr并不是真实客户端IP。

场景3

  为了更方便的获取真实客户端IP,可以使用nginx http_realip_module模块解决,在安装nginx时通过--with-http_realip_module安装该模块。NginxProxy配置和场景2一样。

Nginx Backend
192.168.107.114 nginx.conf
real_ip_header X-Forwarded-For;
set_real_ip_from 192.168.0.0/16;
real_ip_recursive on; 

location /test {
    default_type text/html;
    charset gbk;
    echo "$remote_addr || $http_x_real_ip  ||$http_x_forwarded_for";
}

  当访问服务时,输出结果为:

192.168.162.16 || 192.168.162.16 || 192.168.162.16, 192.168.107.107

分析

1.X-Real-IP和X-Forwarded-For和场景2一样;
2.使用realip模块后,$remote_addr输出结果为真实客户端IP,可以使用$realip_remote_addr获取最后一个反向代理的IP;
3.real_ip_headerX-Forwarded-For:告知Nginx真实客户端IP从哪个请求头获取,如X-Forwarded-For;
4.set_real_ip_from192.168.0.0/16:告知Nginx哪些是反向代理IP,即排除后剩下的就是真实客户端IP,支持配置具体IP地址、CIDR地址;
5.real_ip_recursive on:是否递归解析,当real_ip_recursive配置为off时,Nginx会把real_ip_header指定的请求头中的最后一个IP作为真实客户端IP;当real_ip_recursive配置为on时,Nginx会递归解析real_ip_header指定的请求头,最后一个不匹配set_real_ip_from的IP作为真实客户端IP。
  如果配置“real_ip_recursive off; ”,则输出结果为:

192.168.107.107 || 192.168.162.16 ||192.168.162.16, 192.168.107.107

总结

1.通过“proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for” 把从真实客户端IP和反向代理IP通过逗号分隔,添加到请求头中;
2.可以在第一个反向代理上配置“proxy_set_header X-Real-IP $remote_addr” 获取真实客户端IP;
3.配合realip模块从X-Forwarded-For也可以获取到真实客户端IP。
  在整个反向代理链条的第一个反向代理可以不配置“proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for”,否则客户端可以伪造X-Forwarded-For从而伪造客户端真实IP,如果服务端使用X-Forwarded-For第一个IP作为真实客户端IP,则就出问题了。如果通过配置X-Real-IP请求头或者配合realip模块也不会出现该问题。如果自己解析X-Forwarded-For的话,记得使用realip算法解析,而不是取第一个。
当我们进行限流时一定注意限制的是真实客户端IP,而不是反向代理IP,我遇到过很多同事在这块出问题的。

  想及时获得更多精彩文章,可在微信中搜索“博文视点”或者扫描下方二维码并关注。

时间: 2024-11-03 15:46:41

反向代理与 Real-IP 和 X-Forwarded-For的相关文章

利用kangle反向代理解决一级和二级域名同一个IP,不同服务器,不同网站的问题

也许你看到这个题目比较长,但是为了能清楚我要表达的意思,只能这样了. 呵呵,这个问题算是让我纠结了一个周左右了,不过今天这个问题终于得到了圆满解决. 问题也如我标题所列出来的一样,我现在在公司内网有两台服务器一台是公司网站,一台是公司的OA系统.而公司对外只有一个IP地址,但是现在要求通过a.com可以访问公司的网站,oa.a.com访问公司的OA系统. 要解决这个问题,我们可以使用反向代理服务器来解决.如果说是在linux系统下,那么解决方案是比较多的.例如squid.nginx等.当然在wi

Nginx 反向代理 如何在web应用中获取用户ip

转载:http://blog.csdn.net/bao19901210/article/details/52537279 问题背景: 在实际应用中,我们可能需要获取用户的ip地址,比如做异地登陆的判断,或者统计ip访问次数等,通常情况下我们使用request.getRemoteAddr()就可以获取到客户端ip,但是当我们使用了nginx作为反向代理后,使用request.getRemoteAddr()获取到的就一直是nginx服务器的ip的地址,那这时应该怎么办? part1:解决方案 我在查

Nginx反向代理+DNS轮询+IIS7.5 千万PV 百万IP 双线 网站架构案例_nginx

Nginx  ("engine x") 是一个高性能的 HTTP 和反向代理服务器,也是一个 IMAP/POP3/SMTP 代理服务器. Nginx 是由 Igor Sysoev 为俄罗斯访问量第二的 Rambler.ru 站点开发的,它已经在该站点运行超过两年半了.Igor 将源代码以类BSD许可证的形式发布. Nginx 的中文维基:http://wiki.codemongers.com/NginxChs 在高并发连接的情况下,Nginx是Apache服务器不错的替代品.Nginx

Nginx配置负载均衡及反向代理

简单介绍: 1.Nginx优点 Nginx 负均衡实现比较简单,可配置性很强,可以按URL做负载均衡,默认对后端有健康检查的能力.后端机器少的情况下(少于10台)负载均衡能力表现好.其优点主要有: 1)功能强大,支持高并发连接,内存消耗少:官方测试能够支撑5万并发连接,在实际生产环境中跑到2-3 万并发连接数,且在3万并发连接下,开启的10个Nginx 进程才消耗150M内存(15M*10=150M). 2)成本低廉:Nginx 为开源软件,免费使用. 3)Nginx 工作在网络的7 层,所以它

Linux防火墙上的Apache反向代理

[导读]本文着重介绍在企业防火墙上安装具有代理和重写规则功能的Web服务器--Apache的方法,以及编译和设置Apache的具体步骤.在成功安装后,弹性的虚拟主机设置可以允许外部用户通过防火墙访问内部局域网上多个Web服务器. 一.测试环境与网络结构 本文所使用的测试环境是Redhat Linux 7.2.Apache 1.3.24,公司域名假设是company.com. 公司的典型网络构造如附图所示. 注意: 附图中的防火墙上安装了2块网卡,其中e0端口的外部公共地址为1.2.3.4,e1端

基于反向代理的Web缓存加速——可缓存的CMS系统设计

web|缓存|设计 对于一个日访问量达到百万级的网站来说,速度很快就成为一个瓶颈.除了优化内容发布系统的应用本身外,如果能把不需要实时更新的动态页面的输出结果转化成静态网页来发布,速度上的提升效果将是显著的,因为一个动态页面的速度往往会比静态页面慢2-10倍,而静态网页的内容如果能被缓存在内存里,访问速度甚至会比原有动态网页有2-3个数量级的提高. 动态缓存和静态缓存的比较 基于反向代理加速的站点规划 基于apache mod_proxy的反向代理加速实现 基于squid的反向代理加速实现 面向

使用Nginx反向代理实现简单的负载均衡

Nginx反向代理的原理优点: 反向代理可以简单的理解为:代理服务器来接收internet上的服务器请求,然后将请求转发给内部的服务器上,然后将结果返回给internet上请求的客户端,所以代理服务器对外表现出来的只是一台服务器.反向代理服务器也称为Web服务器加速,针对web服务器提供加速功能.他作为代理服务器,并不针对浏览器用户,而是针对一台或者多台特定的web服务器.可以缓存web的页面,降低web服务器的访问量,从而来降低web服务器的负载,实施反向代理,只要将反向代理设备放置在一台或多

Linux Squid的反向代理

一.基本原理 1.公网中的客户机 client 200.168.10.2 2.squid反向代理服务器 eth0 200.168.10.2 eth1 192.168.10.1 3.内部web服务器 web 192.168.10.2 二.修改squid.conf文件 #配置虚拟80端口,防止数据报文直接丢失 http_port 200.168.10.1:80 vhost #重定向的web服务器 0表示不使用上一级缓存 cache_peer 192.168.10.2 parent 80 0 orig

Nginx中实现反向代理

Nginx的2种用途 静态内容的web服务器: 反向代理服务器: Nginx作为反向代理的特点 接收用户请求是异步的,即先将用户请求全部接收下来,再一次性发送后后端web服务器,极大的减轻后端web服务器的压力: nginx代理和后端web服务器间无需长连接: 发送响应报文时,是边接收来自后端web服务器的数据,边发送给客户端的: 涉及的模块 Proxy:标准的HTTP模块,实现反向代理功能 Upstream:标准的HTTP模块,对后端web服务器调度做负载均衡功能: FastCGI:标准HTT

用Squid实现反向代理的方法

代理服务器是使用非常普遍的一种将局域网主机联入互联网的一种方式,使用代理上网可以节约紧缺的IP地址资源,而且可以阻断外部主机对内部主机的访问,使内部网主机免受外部网主机的攻击.但是,如果想让互联网上的主机访问内部网的主机资源(例如:Web站点),又想使内部网主机免受外部网主机攻击,一般的代理服务是不能实现的,需要使用反向代理来实现. 本文将详细介绍反向代理服务的概念以及如何利用反向代理服务器提高WEB服务器的性能和安全性. 一.反向代理的概念 什么是反向代理呢?其实,反向代理也就是通常所说的WE