Nginx网站使用CDN之后禁止用户真实IP访问的方法
各位扥扥早,包子油条豆浆带一份!
起立!
好了废话不多说了,如果有用请转发出去。
一、真假难辨
如何禁止访问,我们先了解下常见的3种网站访问模式:
用户直接访问对外服务的普通网站
浏览器 --> DNS解析 --> WEB数据处理 --> 数据吐到浏览器渲染展示
用户访问使用了CDN的网站
浏览器 --> DNS解析 --> CDN节点 --> WEB数据处理 --> 数据吐到浏览器渲染展示
用户通过代理上网访问了我们的网站
浏览器 --> 代理上网 --> DNS解析 --> 上述2种模式均可能
对于第一种模式,我要禁止这个用户的访问很简单,可以直接通过 iptables 或者 Nginx的deny指令来禁止均可:
iptabels:
iptables -I INPUT -s 用户ip -j DROP
Nginx的deny指令:
语 法: deny address | CIDR | unix: | all;
默认值: —
配置段: http, server, location, limit_except
顺 序:从上往下
Demo:
location / {
deny 用户IP或IP段;
}
但对于后面2种模式就无能为力了,因为iptables 和 deny 都只能针对直连IP,而后面2种模式中,WEB服务器直连IP是CDN节点或者代理服务器,此时使用 iptable 或 deny 就只能把 CDN节点 或代理IP给封了,可能误杀一大片正常用户了,而真正的罪魁祸首轻轻松松换一个代理IP又能继续请求了。
那我们可以通过什么途径去解决以上问题呢?
要拿到用户真实IP,只要在Nginx的http模块内加入如下配置:
#获取用户真实IP,并赋值给变量$clientRealIP
map $http_x_forwarded_for $clientRealIp {
"" $remote_addr;
~^(?P<firstAddr>[0-9\.]+),?.*$ $firstAddr;
}
那么,$clientRealIP就是用户真实IP了,其实就是匹配了 $http_x_forwarded_for 的第一个值,具体原理前文也简单分享过:
其实,当一个 CDN 或者透明代理服务器把用户的请求转到后面服务器的时候,这个 CDN 服务器会在 Http 的头中加入一个记录
X-Forwarded-For : 用户IP, 代理服务器IP
如果中间经历了不止一个代理服务器,这个记录会是这样
X-Forwarded-For : 用户IP, 代理服务器1-IP, 代理服务器2-IP, 代理服务器3-IP, ….
可以看到经过好多层代理之后, 用户的真实IP 在第一个位置, 后面会跟一串中间代理服务器的IP地址,从这里取到用户真实的IP地址,针对这个 IP 地址做限制就可以了。
而且代码中还配合使用了 $remote_addr,因此$clientRealIP 还能兼容上文中第1种直接访问模式,不像 $http_x_forwarded_for 在直接访问模式中将会是空值!
所以,$clientRealIP 还能配置到 Nginx 日志格式中,替代传统的 $remote_addr 使用,推荐!
三、隔山打牛
既然已经拿到了真实IP,却不能使用 iptables 和 deny 指令,是否无力感油然而生?
哈哈,在强大的 Nginx 面前只要想得到,你就做得到!通过对 $clientRealIP 这个变量的判断,Nginx就能实现隔山打牛的目的,而且规则简单易懂:
#如果真实IP为 121.42.0.18、121.42.0.19,那么返回403
if ($clientRealIp ~* "121.42.0.18|121.42.0.19") {
#如果你的nginx安装了echo模块,还能如下输出语言,狠狠的发泄你的不满(但不兼容返回403,试试200吧)!
#add_header Content-Type text/plain;
#echo "son of a bitch,you mother fucker,go fuck yourself!";
return 403;
break;
}
把这个保存为 deny.conf ,上传到 Nginx 的 conf 文件夹,然后在要生效的网站 server 模块中引入这个配置文件,并 Reload 重载 Nginx 即可生效:
#禁止某些用户访问
include deny.conf;
如果再想添加其他要禁止的IP,只需要编辑这个文件,插入要禁止的IP,使用分隔符 | 隔开即可,记得每次修改都需要 reload 重载 Nginx才能生效。
到了演示最后了,不知道是否帮助到各位?
如果扥扥们有什么问题,可以文章留言。
有事留言,无事点赞,有用转发!