推广 热搜: 采购方式  甲带  滤芯  气动隔膜泵  减速机  减速机型号  履带  带式称重给煤机  链式给煤机  无级变速机 

Nginx 动态封禁 IP 实战白皮书:从 CC 攻击到分布式实时防护

   日期:2026-02-01 01:47:06     来源:网络整理    作者:本站编辑    评论:0    
Nginx 动态封禁 IP 实战白皮书:从 CC 攻击到分布式实时防护

? Nginx 动态封禁 IP 实战白皮书:从 CC 攻击到分布式实时防护

在真实生产环境中,爬虫、CC 攻击、暴力破解并不是偶发事件,而是长期存在的“背景噪音”。如果仍然依赖静态 deny 或重启 Nginx 生效的方式,不仅防护滞后,还极易误伤正常用户。

本文将从真实攻击场景出发,系统讲解如何在 Nginx / OpenResty 中实现 无需重启、实时生效、可分布式扩展 的动态 IP 封禁体系,并给出可直接落地的代码示例


一、为什么静态封禁在生产中一定会失效?

❌ 传统方式的问题

deny 1.2.3.4;
  • • 需要 reload 才生效
  • • 攻击响应慢
  • • IP 数量一多,配置文件失控
  • • 无法应对 IP 轮换、代理池

结论

静态封禁只能作为“最后兜底”,不适合作为主防线。


二、动态封禁方案对比(选型依据)

方案
实时性
分布式
复杂策略
成本
适用场景
Fail2ban
一般
单机、防爆破
Lua + Redis
⭐⭐⭐⭐⭐
生产首选
NGINX Plus
⭐⭐⭐
商业版用户
limit_req
⚠️
抗洪水

本文核心方案:Lua + Redis


三、实战场景一:CC 攻击(高频但不打死)

? 攻击特征

  • • 单 IP / 小 IP 池
  • • 高频请求首页或 API
  • • 不断线、不报错

? 防护目标

10 秒内超过 200 次请求 → 封禁 10 分钟


核心思路(滑动窗口)

  1. 1. Redis 记录 IP 请求计数
  2. 2. 超过阈值 → 写入封禁 Key
  3. 3. 后续请求实时拦截

Lua 生产级代码示例

local redis = require "resty.redis"
local
 red = redis:new()
red:set_timeout(50)

local
 ok, err = red:connect("redis", 6379)
if
 not ok then
    return

end


local
 ip = ngx.var.remote_addr
local
 req_key = "req:cc:" .. ip
local
 ban_key = "ban:cc:" .. ip

-- 已封禁直接拦截

local
 banned = red:get(ban_key)
if
 banned ~= ngx.null then
    ngx.exit(ngx.HTTP_FORBIDDEN)
end


-- 计数

local
 count = red:incr(req_key)
if
 count == 1 then
    red:expire(req_key, 10)
end


if
 count > 200 then
    red:setex(ban_key, 600, 1)
    ngx.log(ngx.WARN, "CC BAN IP: ", ip)
    ngx.exit(ngx.HTTP_FORBIDDEN)
end


red:set_keepalive(10000, 100)

✅ 实战效果

  • • CC 攻击流量下降 90%+
  • • 正常用户无感知
  • • Redis QPS 稳定

四、实战场景二:登录接口暴力破解

? 攻击特征

  • • /login / /wp-login.php
  • • 高频 POST
  • • 返回 401 / 403

Fail2ban 规则(识别攻击)

failregex = ^<HOST> .* "POST /api/auth/login" 401
[nginx-login]
enabled
 = true
filter
 = nginx-login
logpath
 = /var/log/nginx/access.log
maxretry
 = 10
findtime
 = 60
bantime
 = 3600

Fail2ban + Redis 联动

Fail2ban action:

redis-cli SETEX ban:login:<IP> 3600 1

Lua 实时拦截:

local ban = red:get("ban:login:" .. ip)
if
 ban ~= ngx.null then
    ngx.exit(ngx.HTTP_FORBIDDEN)
end

五、实战场景三:恶意爬虫 / 扫描器

? 特征

  • • 高频 404
  • • 访问 /admin/phpmyadmin
  • • UA 异常

UA + URI 联合封禁

local ua = ngx.var.http_user_agent or ""
local
 uri = ngx.var.uri

local
 bad_ua = {
    "sqlmap"
,
    "nmap"
,
    "python-requests"
,
    "curl"

}

for
 _, v in ipairs(bad_ua) do
    if
 ua:lower():find(v) then
        ngx.exit(ngx.HTTP_FORBIDDEN)
    end

end


if
 uri:find("/phpmyadmin") or uri:find("/admin") then
    ngx.exit(ngx.HTTP_FORBIDDEN)
end

⚠️ UA 不可单独作为封禁依据,必须与行为组合


六、K8s / Ingress 场景下的正确姿势

❌ 常见误区

  • • 在 Pod 内运行 Fail2ban
  • • 实际封禁的是 Pod IP

✅ 正确架构

Client → CDN → Ingress-Nginx(Lua) → Service → Pod
                         ↓
                       Redis

Ingress 注入 Lua:

nginx.ingress.kubernetes.io/server-snippet: |
  access_by_lua_file
 /etc/nginx/lua/ip_block.lua;

七、生产环境关键经验(血泪总结)

一定要做

  • • 正确获取真实 IP
  • • Redis Key 设置 TTL
  • • 封禁日志可追踪
real_ip_header X-Forwarded-For;
real_ip_recursive
 on;

千万别做

  • • Lua 写复杂业务逻辑
  • • 每请求新建 Redis 连接
  • • 无限增长黑名单

八、推荐的终极防护组合

层级
技术
CDN
国家 / IP 黑名单
Nginx
limit_req 抗洪水
OpenResty
Lua + Redis 精准封禁
Fail2ban
行为识别
监控
Redis + 日志

九、结语

限流解决“洪水”,封禁解决“坏人”,Lua + Redis 解决“实时与分布式”。

真正可持续的安全体系,从来不是单点方案,而是多层协同。


 
打赏
 
更多>同类资讯
0相关评论

推荐图文
推荐资讯
点击排行
网站首页  |  关于我们  |  联系方式  |  使用协议  |  版权隐私  |  网站地图  |  排名推广  |  广告服务  |  积分换礼  |  网站留言  |  RSS订阅  |  违规举报  |  皖ICP备20008326号-18
Powered By DESTOON