【005】Nginx学习笔记-Nginx真实IP

【005】Nginx学习笔记-Nginx真实IP

  • 真实IP
    • 客户端真实IP
    • 深入理解真实IP
      • 实验一
      • 实验二: 多个代理服务器的情况
      • 实验三:利用realip模块获取客户端真实IP
      • 实验四:伪装请求头
  • Reference

真实IP

  1. 配置代理服务器将客户端 IP 传递给后端服务器
    查看后端服务器的访问日志,我们发现日志中记录的客户端 IP 并非真实客户端的 IP,而是代理服务器的 IP 。
    之所以会这样,原因是客户端向代理服务器发起请求后,再由代理服务器向后端服务器发起请求。
    站在后端服务器的角度,代理服务器才是直接通信的“客户端”,所以记录的是代理服务器的 IP,显然,记录这个 IP 是没有意义的。

由于后端服务器和客户端并没有直接的通信,所以客户端的真实 IP 只能通过代理服务器传递给后端服务器。
我们可以在代理服务器上将客户端的 IP 封装到请求报文中发送给后端服务器。
示例:
在代理服务器上配置:

...
    location / {
        proxy_pass http://webs;
        proxy_set_header X-Real-IP $remote_addr;        #  将 $remote_addr 的值封装到请求报文头部的 X-Real-IP 字段中
     }
...

做了以上配置后,再次用客户端访问代理服务器,在后端服务器上抓包,可以看到请求头部有了 X-Real-IP 字段,它的值正是客户端真实 IP

  1. 配置后端 web 服务器记录下客户端真实 IP
    虽然经过以上第1步配置,代理能够将客户端真实 IP 传递过来了,但默认情况下后端服务器并不会在日志中记录请求头部 X-Real-IP 字段的值。
    2-1、后端服务器为 apache 产品
    对于 apache 产品,只需修改配置文件中的 LogFormat 即可:
    LogFormat “%{X-Real-ip}i %l %u %t “%r” %>s %b “%{Referer}i” “%{User-Agent}i”” combined

2-2、后端为 nginx
如果后端为nginx,有两种方法可实现:
A、直接修改 log_format ,将 $remote_addr 改为 $http_x_real_ip 即可

B、安装 real_ip 模块(ngx_http_realip_module),然后修改配置文件:

...
    location / {
            root   html;
            index  index.html index.htm;
            set_real_ip_from 代理服务器IP;
            real_ip_header X-Real-IP;
        }
...

这样配置后,$remote_addr 的值将会从请求报文中的 X-Real-IP 字段中获取。

客户端真实IP

做完上述调度算法的试验后,我们查看apache的连接日志,发现访问到服务器的ip都是代理服务器的ip,这样我们就无法统计客户端的ip了
【005】Nginx学习笔记-Nginx真实IP_第1张图片
我们在nginx代理服务器配置文件做如下操作
【005】Nginx学习笔记-Nginx真实IP_第2张图片
重启nginx ,然后再代理服务器用tcpdump抓包,并且访问代理服务器
【005】Nginx学习笔记-Nginx真实IP_第3张图片

我们抓到了真机的ipreal-ip 192.168.10.1
但是nginx的连接日志仍然没有记录客户端ip,在这里插入图片描述
怎么解决呢,我们在代理服务器端nginx的配置文件内的log_format下添加$http_x_real_ip在这里插入图片描述
我们用不同的虚拟机访问代理服务器,然后再服务器端我们就能看见真实的ip了
在这里插入图片描述
但是apache的日志还没有显示真实ip,所以我们这样更改配置文件
在这里插入图片描述
重启并查看服务器apache的连接日志
在这里插入图片描述

深入理解真实IP

几个关于IP的变量:

$remote_addr     -       直接与服务器通信的客户端的IP地址
$http_x_real_ip    -       从请求报文首部的X-Real-IP字段获取值
$http_x_forwarded_for  -  从请求报文首部的X-Forwarded-For字段获取的值 
$realip_remote_addr  -  最后一个反向代理服务器的IP
$proxy_add_x_forwarded_for  -  如果请求报文首部没有 X-Forwarded-For 字段,则此变量值为“$remote_addr”;
如果请求报文首部有 X-Forwarded-For 字段,则此变量值为 “X-Forwarded-For的值, $remote_addr”。

实验一

实验一: 一个代理服务器的情况
代理服务器: 192.168.10.41
web服务器: 192.168.10.42
客户端: 192.168.10.31

web服务器配置(nginx):

location = /test {
    echo "remote_addr: $remote_addr";
    echo "http_x_forwarded_for: $http_x_forwarded_for";
    echo "http_x_real_ip: $http_x_real_ip";
    echo "real-ip-remote-addr: $realip_remote_addr";
}

1.代理服务器配置一:

location = /test {
    proxy_pass http://192.168.10.42;
}

访问结果:

# curl 192.168.10.41/test
remote_addr: 192.168.10.41
http_x_forwarded_for: 
http_x_real_ip: 
real-ip-remote-addr: 192.168.10.41

2.代理服务器配置二:

location = /test {
    proxy_pass http://192.168.10.42;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

访问结果:

# curl 192.168.10.41/test
remote_addr: 192.168.10.41
http_x_forwarded_for: 192.168.10.31
http_x_real_ip: 192.168.10.31
real-ip-remote-addr: 192.168.10.41

分析: 只有一个代理的情况下$http_x_forwarded_for也记录了客户端的真实IP

实验二: 多个代理服务器的情况

web服务器配置同实验一
在这里插入图片描述

代理服务器一配置

location = /test {
    proxy_pass http://192.168.10.41;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

代理服务器二配置

location = /test {
$http_x_forwarded_for";
    proxy_pass http://192.168.10.42;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

访问结果

# curl 192.168.10.32/test
remote_addr: 192.168.10.41
http_x_forwarded_for: 192.168.10.31, 192.168.10.32    
http_x_real_ip: 192.168.10.32                  #从这里可以看出X-Real-IP被$remote_addr覆盖了,而$remote_addr是proxy2的上一个proxy的IP
real-ip-remote-addr: 192.168.10.41

分析: 如果有多个代理,
第一个代理上的$http_x_forwarded_for记录了客户端的真实IP(X-Forwarded-For字段)
后面代理上记录的是X-Forwarded-For的值及上一个代理的IP,使用","隔开.
$http_x_forwarded_for的值由客户端IP及所经过的所有代理服务器(最后一个除外)的值组成

实验三:利用realip模块获取客户端真实IP

在实验二的基础上,修改web服务器的配置:

location = /test {
    set_real_ip_from 192.168.10.0/24;          #定义可发送真实IP的地址,可以是一个具体地址,也可以是CIDR地址
    real_ip_header X-Forwarded-For;            #指定真实IP从哪个请求头中获取
    real_ip_recursive on;       #是否递归解析,当其值为off时,将把real_ip_header指定请求头中的最后一个IP作为真实IP
    echo "remote_addr: $remote_addr";
    echo "http_x_forwarded_for: $http_x_forwarded_for";
    echo "http_x_real_ip: $http_x_real_ip";
    echo "real-ip-remote-addr: $realip_remote_addr";
}

访问结果

# curl 192.168.10.32/test
remote_addr: 192.168.10.31
http_x_forwarded_for: 192.168.10.31, 192.168.10.32
http_x_real_ip: 192.168.10.32
real-ip-remote-addr: 192.168.10.41

分析: 使用realip模块后,nginx可以通过$remote_addr获取到客户端真实IP

实验四:伪装请求头

在这里插入图片描述

代理服务器一配置
location = /test {
proxy_pass http://192.168.10.41;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

代理服务器二配置
location = /test {
proxy_pass http://192.168.10.42;
proxy_set_header X-Real-IP $http_x_real_ip;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

web服务器配置:
location = /test {
set_real_ip_from 192.168.10.0/24;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
echo “remote_addr: $remote_addr”;
echo “http_x_forwarded_for: $http_x_forwarded_for”;
echo “http_x_real_ip: $http_x_real_ip”;
echo “real-ip-remote-addr: $realip_remote_addr”;
}

访问结果

# curl  -H "X-Real-IP: 10.10.10.11" 192.168.10.32/test
remote_addr: 192.168.10.31
http_x_forwarded_for: 192.168.10.31, 192.168.10.32
http_x_real_ip: 192.168.10.31
real-ip-remote-addr: 192.168.10.41

# curl -H "X-Forwarded-For: 10.10.10.10" -H "X-Real-IP: 10.10.10.11" 192.168.10.32/test
remote_addr: 10.10.10.10
http_x_forwarded_for: 10.10.10.10, 192.168.10.31, 192.168.10.32
http_x_real_ip: 192.168.10.31
real-ip-remote-addr: 192.168.10.41

分析:
当我们改变了x-real-ip的配置后,发现即使一开始将X-Real-IP进行伪装,客户端的真实IP仍然能够正确的传递进来;
而如果一开始对X-Forwarded-For进行伪装,我们获取到的真实IP就不正确了. 为了避免这种情况,我们可以在第一个代理上修改设置,将proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;修改为proxy_set_header X-Forwarded-For $remote_addr;即可


多个代理服务器(nginx)的情况下,想要获取真实IP:
1).通过X-Forwarded-For字段获取:
第一个代理服务器: proxy_set_header X-Forwarded-For $remote_addr;
后面的代理服务器: proxy_set_header X-Forwarded-For KaTeX parse error: Double subscript at position 12: proxy_add_x_̲forwarded_for; …remote_addr即可

2).通过X-Real-IP字段获取:
第一个代理服务器: proxy_set_header X-Real-IP $remote_addr;
后面的代理服务器: proxy_set_header X-Real-IP $http_x_real_ip;
最终服务器修改日志格式中的变量为 $http_x_real_ip即可

Reference

  1. 课堂笔记

你可能感兴趣的:(Linux,Nginx学习笔记,nginx,学习,tcp/ip)