分享

nginx反向代理,后端服务器获取真实ip原理

 Bladexu的文库 2017-09-13

nginx反向代理,后端服务器获取真实ip原理

环境:nginx做反向代理,apache做后端服务器

nginx部分配置代码:

upstream apache{

server 127.0.0.1:8080; # 后端真实服务器地址及端口

}

server {

listen 80;

server_name www.a.com;

root /usr/share/nginx/html;

location / {

proxy_pass http://apache;

proxy_set_header ClientIpGetFromNginx $remote_addr;

}

首先先去看一下nginx内置的变量:http://blog.csdn.net/iinel/article/details/4321383

变量 $remote_addr 代表客户端ip地址

通常来说nginx反向代理会添加一个请求头

proxy_set_header X-Forwarded-For $remote_addr;

以此传递客户端ip到后端服务器。

为了方便理解,我这里改一下头的名称:

proxy_set_headerClientIpGetFromNginx$remote_addr;

此时用浏览器访问一下,去查看后端服务器的访问日志如下

127.0.0.1 – - [01/Sep/2017:10:31:10 +0800] 后面内容省略···

可以看到客户端ip为127.0.0.1也就是nginx的ip,(我nginx和后端服务器在一起)

这样一来获取的ip是错误的,那怎样获取正确ip呢?

先来看一下apache日志格式。

LogFormat “%h %l %u %t \”%r\” %>s %b \”%{Referer}i\” \”%{User-Agent}i\”' combined

LogFormat “%h %l %u %t \”%r\” %>s %b” common

LogFormat “%h %l %u %t \”%r\” %>s %b \”%{Referer}i\” \”%{User-Agent}i\” %I %O” combinedio

CustomLog “logs/access_log” combined

combined、common、combinedio是apache的3中日志格式,默认用 combined 方式

就需要修改

LogFormat “%h %l %u %t \”%r\” %>s %b \”%{Referer}i\” \”%{User-Agent}i\”' combined

LogFormat “%{ClientIpGetFromNginx}i%l %u %t \”%r\” %>s %b \”%{Referer}i\” \”%{User-Agent}i\”' combined

这样一来,就等于从nginx的请求头中取 ClientIpGetFromNginx 变量做为日志开头的ip,即客户端ip

(上面i的意思就是从请求头中取ClientIpGetFromNginx,i就代表请求头)

可以参考apache日志格式:http://blog.sina.com.cn/s/blog_672c5a470100xj7z.html

保存配置,再访问一次,再查看apache的访问日志:

192.168.10.105 – - [01/Sep/2017:11:50:41 +0800] 后面内容省略···

可以看到ip是192.168.10.105,这才是客户端的真实ip。

总结:

nginx获取客户端ip是用$remote_addr变量,这个ip是真实的。

后端服务器如果用$remote_addr获取,那么这个ip其实是nginx的ip。

如果nginx设置了传递变量X-Forwarded-For $remote_addr,那么后端用X-Forwarded-For取真实ip

在没有反向代理或CDN的情况下,是不能用X-Forwarded-For获取客户端ip的。因为浏览器是不会发送这个字段的,如果用程序模拟一个访问,这个值是可以被伪造的。

可能会有个想法,如果设置ip传递为

proxy_set_header remote_addr $remote_addr;

是不是就可以不用修改日志格式或者修改代码了?

结果是不行的,会出现一条这样的日志:

127.0.0.1 – - [01/Sep/2017:13:53:42 +0800] 后面内容省略···

ip是127.0.0.1,是nginx的ip地址。表明$remote_addr是不能伪造的。

在上面的设置,通过php中一个数组 $_SERVER 可以获取到:

$_SERVER 是一个包含了诸如头信息(header)、路径(path)、以及脚本位置(script locations)等等信息的数组。

通过以下php代码可以看到:

<>

foreach ($_SERVER as $k => $v)

{

echo $k . “============” . $v . “
”;

}

保存为1.php,然后去访问这个页面(当然必须有php运行环境)。结果如下

nginx反向代理,后端服务器获取真实ip原理

在阿里云官方网站文档中 https://help.aliyun.com/knowledge_detail/40535.html 也可以看到关于ecs获取客户端ip的方法。是一样的。

知识点:

为啥叫 X-Forwarded-For 而不是别的呢?

这是因为当时的squid之类的缓存软件用的比较广,软件官方文档里就用这个名作为标准了。时间一久,大家都遵守这个习惯了。

在标准请求头中是没有这个变量名的。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多