首页 游戏 软件 资讯 排行榜 专题
首页
业界动态
Nginx 动态封禁 IP 实战:从配置到落地全流程

Nginx 动态封禁 IP 实战:从配置到落地全流程

热心网友
30
转载
2026-04-22

构建动态IP黑名单:Nginx+Lua+Redis实战方案

服务器时不时遭遇恶意爬虫或攻击者的频繁请求,怎么办?一个行之有效的防御策略是建立动态的IP黑名单。简单说,就是把那些“不受欢迎”的IP地址列入名单,在一段时间内拒绝其所有访问请求。这不仅能有效拦截恶意流量,还能灵活设置封禁时长,实现自动化管理。

免费影视、动漫、音乐、游戏、小说资源长期稳定更新! 👉 点此立即查看 👈

需求与环境准备

我们的目标很明确:搭建一个能够动态更新、支持分布式共享、且对应用性能影响极小的IP黑名单系统。在开始动手前,需要准备好以下环境:

服务器系统: CentOS 7 或 Ubuntu 等主流Linux发行版均可。
Redis版本: 5.0.5 或更高。
Nginx版本: 推荐使用集成Lua模块的OpenResty,它让在Nginx中嵌入Lua逻辑变得轻而易举。

设计方案选型

实现IP黑名单,路子其实不少,各有优劣:

1. 操作系统层面(如iptables)
直接在服务器防火墙上动手。优点是拦截彻底,效果立竿见影。但缺点也很明显:每次操作都得登录服务器手动修改配置,既麻烦又难以应对快速变化的攻击,更别提在多台服务器间同步名单了。

2. Web服务器层面(如Nginx)
利用Nginx自身的deny指令或强大的Lua扩展模块。这个方案的魅力在于“动态化”——可以通过程序逻辑实时更新黑名单,并能方便地设置过期时间。一套配置可以分发到多台Nginx服务器,实现分布式封禁。当然,它需要你稍微了解一下Lua脚本和Nginx配置。

3. 应用层面
在业务代码处理请求前,先检查IP是否在黑名单里。这种方式对开发者最友好,容易理解和维护。但问题在于,它增加了应用的逻辑负担,在高并发场景下可能成为性能瓶颈,而且代码容易变得冗长。

综合来看,为了兼顾灵活性、性能和易管理性,Nginx + Lua + Redis的组合脱颖而出。它利用Redis作为中心化的存储和共享点,通过Lua脚本在Nginx的访问阶段进行高效判断,几乎不影响正常业务响应速度。

架构示意图上图清晰地展示了这个工作流程:请求到达Nginx,由Lua脚本查询Redis中的黑名单,并决定是放行还是拒绝。

配置nginx.conf

配置起来并不复杂。首先,在你需要启用IP黑名单的站点配置中,找到对应的location块,加入一行Lua脚本调用即可。

location / {
    # 如果该location下存在静态资源文件,可以考虑做个判断,避免对静态资源也进行黑名单校验
    # if ($request_uri ~ .*\.(html|htm|jpg|js|css)) {
    #     access_by_lua_file /usr/local/lua/access_limit.lua;
    # }
    access_by_lua_file /usr/local/lua/access_limit.lua; # 关键配置,引入Lua限流脚本
    alias /usr/local/web/;
    index index.html index.htm;
}

这里有个小技巧:如果你的这个location主要存放图片、CSS等静态文件,且攻击主要针对动态接口,可以用if判断(注释部分所示)来减少不必要的Redis查询,进一步提升性能。不过,对于大多数场景,直接全局启用也没问题。

编写核心Lua脚本

接下来是重头戏:编写/usr/local/lua/access_limit.lua脚本。这个脚本负责具体的封禁逻辑,其核心思想是:在单位时间内,如果某个IP的访问次数超过阈值,则将其加入黑名单一段时间。

-- access_limit.lua
-- 目标:自动将访问过频的IP加入黑名单封禁一段时间

-- ---------- 配置区 ----------
local pool_max_idle_time = 10000  -- Redis连接池超时回收时间(毫秒)
local pool_size = 100             -- Redis连接池大小
local redis_connection_timeout = 100 -- Redis连接超时时间(毫秒)

local redis_host = "your redis host ip" -- Redis服务器地址
local redis_port = "your redis port"    -- Redis端口
local redis_auth = "your redis auth password" -- Redis认证密码

local ip_block_time = 120         -- IP被封禁的时长(秒)
local ip_time_out = 1             -- 统计访问频率的时间窗口(秒)
local ip_max_count = 3            -- 时间窗口内允许的最大访问次数
-- ---------- 配置结束 ----------

-- 记录错误日志
local function errlog(msg, ex)
    ngx.log(ngx.ERR, msg, ex)
end

-- 将Redis连接归还至连接池
local function close_redis(red)
    if not red then
        return
    end
    local ok, err = red:set_keepalive(pool_max_idle_time, pool_size)
    if not ok then
        ngx.say("redis connect err:", err)
        return red:close()
    end
end

-- 连接Redis
local redis = require "resty.redis"
local client = redis:new()
local ok, err = client:connect(redis_host, redis_port)
if not ok then
    close_redis(client)
    ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) -- 连接失败,返回500错误
end

-- 设置超时
client:set_timeout(redis_connection_timeout)

-- 优化:只有新建的连接才需要认证密码
local connCount, err = client:get_reused_times()
if 0 == connCount then
    local ok, err = client:auth(redis_auth)
    if not ok then
        errlog("failed to auth: ", err)
        return
    end
elseif err then
    errlog("failed to get reused times: ", err)
    return
end

-- 获取客户端真实IP(考虑袋里情况)
local function getIp()
    local clientIP = ngx.req.get_headers()["X-Real-IP"]
    if clientIP == nil then
        clientIP = ngx.req.get_headers()["x_forwarded_for"]
    end
    if clientIP == nil then
        clientIP = ngx.var.remote_addr
    end
    return clientIP
end

local clientIp = getIp();
local incrKey = "limit:count:" .. clientIp -- 用于计数器的Key
local blockKey = "limit:block:" .. clientIp -- 用于标记是否封禁的Key

-- 检查IP是否已被封禁
local is_block, err = client:get(blockKey)
if tonumber(is_block) == 1 then
    ngx.exit(ngx.HTTP_FORBIDDEN) -- 如果已被封禁,直接返回403
    close_redis(client)
end

-- IP访问计数:每次访问+1,如果是首次(值为1),设置计数器过期时间
local ip_count, err = client:incr(incrKey)
if tonumber(ip_count) == 1 then
    client:expire(incrKey, ip_time_out)
end

-- 判断:如果计数超过阈值,则设置封禁标识
if tonumber(ip_count) > tonumber(ip_max_count) then
    client:set(blockKey, 1)
    client:expire(blockKey, ip_block_time)
end

-- 操作完成,释放连接
close_redis(client)

这个脚本的逻辑链条非常清晰:获取IP -> 查是否已封禁 -> 统计访问次数 -> 判断是否触发封禁。所有状态都存储在Redis中,因此多台Nginx服务器可以共享同一份黑名单,实现了分布式防护。

方案总结

至此,一个基于Nginx+Lua+Redis的动态IP黑名单系统就搭建完成了。回顾一下,这个方案有几个突出的优点:

1. 轻量高效: 在Nginx的访问阶段进行拦截,对后端应用服务几乎无感,性能损耗极小。
2. 集中管理: 通过Redis集中存储黑名单,任何服务器上的策略变更都能实时同步,管理起来非常方便。
3. 动态灵活: 封禁策略(如时间窗口、阈值、封禁时长)可以通过修改Lua脚本或Redis数据动态调整,无需重启服务。

扩展思考

1. IP黑名单的典型应用场景

这个功能可不是简单的“关门谢客”,它在多种安全防护场景下都能大显身手:

防御恶意扫描与攻击: 有效拦截那些进行密码暴力破解、SQL注入、XSS跨站脚本测试的IP源。
反爬虫与数据保护: 限制恶意爬虫高频抓取数据,既能减轻服务器负载,也能保护核心数据资产。
缓解DDoS攻击: 虽然无法应对海量分布式攻击,但对于小规模或持续性的攻击源,将其IP加入黑名单可以快速切断流量,为其他防护措施争取时间。
业务风控: 例如,限制同一IP在秒杀活动中的抢购次数,或者在投票系统中防止刷票。

2. 高级功能与优化方向

基础功能实现后,还可以在此基础上做更多文章,让防护体系更智能、更健壮:

智能异常检测与自动封禁: 结合日志分析,可以建立更复杂的模型。例如,不仅检测访问频率,还分析访问路径、User-Agent等特征,自动识别并封禁有异常行为的IP。
引入白名单机制: 有黑就有白。将可信的IP(如公司出口IP、合作伙伴IP)加入白名单,确保其访问永远不会被误拦截,这对于运维和内部测试至关重要。
验证码挑战: 对于可疑但又不确定是恶意攻击的IP(例如频率略高于阈值),可以不直接封禁,而是弹出验证码进行人机验证。通过则正常访问,失败则加入黑名单。
数据统计与分析: 将黑名单的触发记录、封禁时长、IP来源等信息进行统计和分析。这些数据是优化防护策略的宝贵依据,能帮你回答诸如“攻击主要来自哪个地区?”“哪种攻击模式最常见?”等问题。

安全防护是一个持续的过程。通过不断迭代和优化IP黑名单策略,你可以为服务器和应用构筑起一道更加灵活、智能的动态防线。

来源:https://server.51cto.com/article/837353.html
免责声明: 游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。

相关攻略

Nginx 动态封禁 IP 实战:从配置到落地全流程
业界动态
Nginx 动态封禁 IP 实战:从配置到落地全流程

构建动态IP黑名单:Nginx+Lua+Redis实战方案 服务器时不时遭遇恶意爬虫或攻击者的频繁请求,怎么办?一个行之有效的防御策略是建立动态的IP黑名单。简单说,就是把那些“不受欢迎”的IP地址列入名单,在一段时间内拒绝其所有访问请求。这不仅能有效拦截恶意流量,还能灵活设置封禁时长,实现自动化管

热心网友
04.22
Nginx之外为何还需网关?两大组件核心差异解析
科技数码
Nginx之外为何还需网关?两大组件核心差异解析

Nginx是一款很强大的高性能Web和反向代理服务,它是用C语言开发的,其核心优势占有内存少,并发能力强,非常适合应用在高并发场景、静态资源托管和请求的负载均衡等等。 在微服务架构普及的当下,即使项

热心网友
02.02
Nginx深色模式支持优化:解决用户夜间“亮瞎眼”痛点
业界动态
Nginx深色模式支持优化:解决用户夜间“亮瞎眼”痛点

3 月 18 日消息,名为 anvme 的用户昨日于 Nginx 的 Github 页面上,提交了为 Nginx 错误页面添加深色模式支持的请求,但这项请求于昨天被 Nginx 的开发者拒绝。该用

热心网友
12.20
Nginx 平滑升级的实战指南!(含备份+业务0中断+回滚)
科技数码
Nginx 平滑升级的实战指南!(含备份+业务0中断+回滚)

在实际生产环境,安全部门一般都会定期去扫描程序漏洞,基本都需要升级版本。今天我们就分享一下Nginx如何平滑升级,做到零中断。 今天分享一下Nginx如何平滑升级,做到零中断。在实际生产环境,安全部

热心网友
12.15
Nginx百万并发性能优化实战,提升100倍吞吐量
科技数码
Nginx百万并发性能优化实战,提升100倍吞吐量

Nginx 的并发能力由其进程模型决定,关键在于合理配置 Worker 进程数和每个进程的连接数。进程与连接模型:Nginx 的总并发能力(理论最大值)约等于: worker_processes​

热心网友
10.05

最新APP

宝宝过生日
宝宝过生日
应用辅助 04-07
台球世界
台球世界
体育竞技 04-07
解绳子
解绳子
休闲益智 04-07
骑兵冲突
骑兵冲突
棋牌策略 04-07
三国真龙传
三国真龙传
角色扮演 04-07

热门推荐

连亏五个季度后,光伏板块终于盈利了
科技数码
连亏五个季度后,光伏板块终于盈利了

三季报收官,光伏企业交出了近年难得的尚佳成绩 三季报发布完毕,光伏行业总算交出了一份近年来难得的、还算不错的成绩单。市场等这一刻,确实等了挺久。 根据Choice光伏设备板块收录的78家企业财报,整个板块三季度的净利润达到了7 58亿元。这个数字怎么看?不妨对比一下:就在二季度,板块的净亏损还高达4

热心网友
04.22
天龙三号首飞失利:与猎鹰9号对标之路,归零迭代成破局关键
科技数码
天龙三号首飞失利:与猎鹰9号对标之路,归零迭代成破局关键

北京天兵科技天龙三号火箭首飞失利解析 最近,北京天兵科技自主研发的天龙三号大型液体运载火箭,在酒泉卫星发射中心执行首次飞行任务时遭遇失利,这无疑是给国内商业航天关注者带来了一次震动。这款被寄予厚望的火箭,瞄准的是近地轨道20吨级的可回收运力,其设计初衷是通过低成本、高频次的发射模式,抢占一箭36星组

热心网友
04.22
开发者自建48台Mac mini集群,撑起Overcast播客转录
科技数码
开发者自建48台Mac mini集群,撑起Overcast播客转录

苹果芯片实战:48台Mac mini搭建本地AI集群,如何碘伏云端语音识别? 最近科技圈有个挺有意思的消息。知名播客应用Overcast的开发者Marco Arment,自己动手搭了个“大家伙”——一个由48台苹果Mac mini组成的服务器集群。关键是,这个集群没走寻常路,它完全绕开了云端AI服务

热心网友
04.22
领克10+与10全球首秀:高效补能搭配赛道王者,开启纯电高性能新篇
科技数码
领克10+与10全球首秀:高效补能搭配赛道王者,开启纯电高性能新篇

纯电赛道再进化:领克10系列如何重新定义“运动轿车”? 如果问,纯电时代最让人怀念传统燃油车的是什么?很多人会把票投给两件事:说走就走的补能,和随心所欲的操控。最近,领克用一场全球首秀给出了自己的答案。旗下全新的中大型运动轿车领克10,以及更极致的性能版本领克10+联袂登场。这不仅仅是两款新车,更像

热心网友
04.22
Apple Vision Pro新专利曝光:将实现按需定制与组件更换
科技数码
Apple Vision Pro新专利曝光:将实现按需定制与组件更换

苹果正酝酿一款“可自定义”的Vision Pro,核心框架支持模块化拼装 一则来自供应链和专利领域的消息,引起了科技圈的关注。4月8日,有外媒报道指出,苹果似乎并不满足于当前的一体化设计思路,其正在深入探索如何打造一款高度可自定义的Apple Vision Pro。未来的VR AR头显,用户或许能像

热心网友
04.22