当服务前面有多层代理服务,例如CDN,经过多层代理服务器,服务这边显示的IP 为上层代理的IP,而不是用户ip
二、使用realip获取已确定多层代理的IP或IP段
nginx官方文档:
https://nginx.org/en/docs/http/ngx_http_realip_module.html
优点:程序不需要改动,直接使用remote_addr即可获取IP地址
缺点:ip地址有可能被伪装,而且需要知道所有代理节点的ip地址或者ip段
set_real_ip_from :真实服务器上一级代理的IP地址或者IP段,可以写多行
real_ip_header :从哪个header头检索出要的IP地址
real_ip_recursive :递归排除IP地址,ip串从右到左开始排除 set_real_ip_from 里面出现的IP,如果出现了未出现这些ip段的IP,那么这个IP将被认为是用户的IP,赋值到 remote_addr 变量。
例如,服务器$http_x_forwarded_for获取到的IP地址串如下:
117.61.240.104,10.0.32.45,10.0.32.41,10.0.32.42
在real_ip_recursive off或者不设置的情况下
192.168.50.121出现在set_real_ip_from中,排除掉,接下来的ip地址便认为是用户的ip地址
如下配置:
set_real_ip_from 10.0.32.45;
set_real_ip_from 10.0.32.41;
set_real_ip_from 10.0.32.42;
real_ip_header X-Forwarded-For;
real_ip_recursive off;
那么获取的IP为10.0.32.41
real_ip_recursive on开启,每层代理的IP 都加上,如果是同网段,可以写成IP段
set_real_ip_from 10.0.32.45;
set_real_ip_from 10.0.32.41;
set_real_ip_from 10.0.32.42;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
在real_ip_recursive on的情况下
10.0.32.45,10.0.32.41,10..0.32.42都出现在set_real_ip_from中,仅仅117.61.240.104没出现,那么他就被认为是用户的ip地址,并且赋值到remote_addr变量
配置可以添加在http, server, location 下
注意问题
设置后 $http_x_forwarded_for 和 $proxy_add_x_forwarded_for 变量的不同
$remote_addr 会添加到 $proxy_add_x_forwarded_for 变量中,$proxy_add_x_forwarded_for 就会有重复的IP
$http_x_forwarded_for 变量默认是比$proxy_add_x_forwarded_for 少一层,这时与
$remote_addr 相同为用户真实IP
最后的配置
...
location / {
# 限制内网
set_real_ip_from 10.0.32.45;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
allow 10.0.0.0/8;
deny all;
proxy_pass http://demo;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $http_x_forwarded_for;
}
...
三、获取x-forwarded-for头不确定多层代理的IP时
优点:可以获取到用户的IP地址
缺点:程序需要改动,以及用户IP有可能是伪装的
通过多层代理时,而且不知道多层代理的真实地址是多少时,默认的 $remote_addr 记录的是上层代理服务器的IP, $http_x_forwarded_for 第一位IP为用户的真实IP, 后面为每层代理服务器的IP, 所以获取 $http_x_forwarded_for 记录的第一层IP,赋值给新定义 $client_real_ip 为用户真实IP
1、单个IP或者IP段匹配
vim nginx.conf
http {
....
....
....
## 获取多层代理用户真实IP
map $http_x_forwarded_for $client_real_ip {
"" $remote_addr;
~^(?P<firstAddr>[0-9\.] ),?.*$ $firstAddr;
}
....
....
}
vim conf.d/demo.conf
server{
listen 80;
.......
server_name aptly.uniontech.com ;
........
location /api {
# 没有代理时的配置
allow 10.0.0.0/8;
deny all;
# 匹配远程用户真实IP
if ($client_real_ip !~ "10.*.*.*") {
return 403;
}
proxy_pass http://aptly_api;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
2、多个IP时,访问权限设置
一层代理时使用 $http_x_forwarded_for 获取用户IP
map $http_x_forwarded_for $rbac_access {
...
}
多层代理时,使用前面定义的 $client_real_ip 获取用户IP进行访问控制
map $client_real_ip $rbac_access {
default false; # 默认false拒绝
~*10.*.*.* true; # 内网IP
115.28.139.68 true; # 商店
121.36.167.218 true; # hwy-chinauos-02
159.138.53.176 true; # bbs-next.deepin.org
47.56.88.11 true; # bbs.chinauos.com
114.55.93.175 true; # k8s
47.97.105.51 true; # k8s
47.96.99.187 true; # 阿里云集群预生产环境
120.27.220.167 true; # www.chinauos.com
47.242.84.233 true; # uniontech hk bbs.deepin.org
47.75.108.56 true; # uniontech hk bbs.deepin.org
123.116.158.134 true; # 北京普天
121.196.167.180 true; # 深圳 商店测试服务器
47.111.86.15 true; # k8s store 商店 测试
113.57.152.160 true; # 武汉联通出口
116.62.132.68 true; # 阿里云
47.115.116.186 true; # 消费者事业部 应用商店CMS管理平台
}
server{
......
......
location / {
## 匹配map, 不为ture, 返回403拒绝
if ( $rbac_access = 'false') { return 403; }
proxy_pass http://rbac10002;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
......
}
,