You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过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
  • 避免误封内部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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 09:37:46