如何通过Nginx配置结合蜜罐匹配URI并封禁请求IP?
实现Nginx蜜罐联动防火墙封禁恶意IP
这个需求很典型——用蜜罐路径钓取恶意扫描,再联动防火墙封禁IP,比单纯拒绝请求威慑力强多了。Nginx本身没法直接修改系统防火墙规则,所以我们需要把Nginx的请求捕获和系统防火墙工具(比如iptables/firewalld)结合起来,下面给你两种可行方案:
方案一:使用Nginx Lua模块(推荐,高性能)
如果你的Nginx是基于OpenResty编译的,或者单独安装了ngx_http_lua_module,这个方案性能最优,适合高并发场景。
1. Nginx配置修改
http { # 创建共享内存字典,用来临时存储已封禁IP,避免重复触发封禁逻辑 lua_shared_dict ip_blacklist 10m; server { listen 80; server_name your-domain.com; # 匹配恶意蜜罐路径 location ~* ^/(admin|wp-admin|control|mysqladmin)/?$ { access_by_lua_block { -- 获取客户端IP local client_ip = ngx.var.remote_addr local blacklist = ngx.shared.ip_blacklist local is_banned = blacklist:get(client_ip) -- 只有未封禁的IP才执行封禁逻辑 if not is_banned then -- 24小时封禁逻辑:后台添加iptables规则,86400秒后自动删除 local ban_cmd = string.format( "/usr/sbin/iptables -A INPUT -s %s -j DROP && sleep 86400 && /usr/sbin/iptables -D INPUT -s %s -j DROP &", client_ip, client_ip ) -- 如果要永久封禁,替换成下面的命令: -- local ban_cmd = string.format("/usr/sbin/iptables -A INPUT -s %s -j DROP &", client_ip) -- 执行封禁命令 local handle = io.popen(ban_cmd) handle:close() -- 将IP存入共享字典,24小时后自动过期 blacklist:set(client_ip, true, 86400) end -- 返回404伪装路径不存在,迷惑攻击者 ngx.exit(404) } } # 你的其他正常站点配置... } }
关键说明
lua_shared_dict:用共享内存记录已封禁IP,避免同一个IP多次触发封禁脚本,减少系统负载- 后台执行封禁命令:用
&把命令放到后台,不会阻塞Nginx处理请求 - 伪装返回码:返回404让攻击者以为路径真的不存在,不会察觉这是蜜罐
方案二:使用Shell脚本+Nginx Exec指令(适合无Lua模块的环境)
如果你的Nginx没装Lua模块,用这种方案更简单,不需要重新编译Nginx。
1. 编写IP封禁脚本
创建/usr/local/bin/ban_ip.sh,内容如下:
#!/bin/bash CLIENT_IP="$1" BAN_DURATION=86400 # 24小时,单位秒 # 检查IP是否已经被封禁,避免重复添加规则 /usr/sbin/iptables -C INPUT -s "$CLIENT_IP" -j DROP > /dev/null 2>&1 if [ $? -ne 0 ]; then # 24小时封禁:后台执行添加规则+定时删除的逻辑 ( /usr/sbin/iptables -A INPUT -s "$CLIENT_IP" -j DROP sleep "$BAN_DURATION" /usr/sbin/iptables -D INPUT -s "$CLIENT_IP" -j DROP ) & # 永久封禁的话,替换成下面一行: # /usr/sbin/iptables -A INPUT -s "$CLIENT_IP" -j DROP fi
给脚本添加执行权限:
chmod +x /usr/local/bin/ban_ip.sh
2. Nginx配置修改
server { listen 80; server_name your-domain.com; location ~* ^/(admin|wp-admin|control|mysqladmin)/?$ { # 调用封禁脚本,传入客户端IP exec /usr/local/bin/ban_ip.sh $remote_addr; # 返回404伪装路径不存在 return 404; } # 你的其他正常站点配置... }
重要注意事项
防火墙规则持久化:
iptables规则重启后会丢失,你需要配置持久化:- Debian/Ubuntu:安装
netfilter-persistent,用netfilter-persistent save保存规则 - CentOS/RHEL:安装
iptables-services,启用iptables服务
如果用firewalld代替iptables,把脚本里的iptables命令换成firewalld的富规则即可: - 24小时封禁:
firewall-cmd --add-rich-rule='rule family="ipv4" source address="$CLIENT_IP" reject' --timeout=$BAN_DURATION - 永久封禁:
firewall-cmd --add-rich-rule='rule family="ipv4" source address="$CLIENT_IP" reject' --permanent && firewall-cmd --reload
- Debian/Ubuntu:安装
避免误封内部IP:
如果你有内部IP段需要排除,在Nginx里先过滤:location ~* ^/(admin|wp-admin|control|mysqladmin)/?$ { set $ban_flag 1; # 排除内部IP段,比如192.168.0.0/24 if ($remote_addr ~* ^192\.168\.0\.) { set $ban_flag 0; } if ($ban_flag = 1) { exec /usr/local/bin/ban_ip.sh $remote_addr; # 或者Lua逻辑 } return 404; }权限问题:
Nginx运行用户(通常是nginx或www-data)需要有执行防火墙命令的权限,你可以通过sudo配置免密执行:
编辑sudoers文件(visudo),添加一行:nginx ALL=(ALL) NOPASSWD: /usr/sbin/iptables, /usr/bin/firewalld然后把脚本里的命令改成
sudo /usr/sbin/iptables ...即可。
内容的提问来源于stack exchange,提问作者snh_nl
相关产品推荐
相关产品推荐

