使用 Nginx 实现动态封禁 IP,防止恶意爬虫、暴力破解和 SQL 注入等攻击,可采用两种方案:操作系统层面的拦截(iptables)或 Web 服务器层面的拦截(Nginx + Lua)。
聊一个我最近处理的技术难题——如何用 Nginx 实现动态封禁 IP,防止一些讨厌的爬虫或者恶意用户对你的网站进行恶意攻击。
想必大家也遇到过那些爬虫一遍又一遍疯狂请求服务器,吃掉了大量的带宽资源,或者有些恶意用户尝试用暴力破解方式登陆,着实让人头疼。
幸好,Nginx 和 Lua 结合 Redis,给我们提供了一个既高效又灵活的方案。
1. 背景与需求
有时候,你的服务器会遭遇一些恶意的攻击,常见的就是爬虫、暴力破解、SQL 注入,甚至 DDoS 攻击。
这些行为不仅增加了服务器负担,还可能导致资源浪费,甚至直接造成服务中断。解决这些问题的一种方式就是通过 IP 封禁,尤其是对于那些恶意访问频繁的 IP 地址。封禁的策略应该是动态的,可以随时添加和移除 IP,同时还要控制封禁的时长,以避免误伤正常用户。
我们希望通过以下几个步骤来实现这个目标:
封禁爬虫与恶意用户请求:识别并封禁那些频繁请求且行为恶意的 IP 地址。
建立动态 IP 黑名单:这个黑名单需要能动态更新,支持实时封禁。
封禁失效时间设置:封禁的 IP 不可能永远存在黑名单中,我们需要设置一个失效时间,自动解封。
2. 方案设计
解决这个问题的方案有好几种,每种方法都有其优缺点。
我们可以从操作系统、Web 服务器或应用层面入手,选择适合的技术栈。下面我们分析一下每种方案。
方法 1:操作系统层面的拦截(iptables)
iptables 是 Linux 系统自带的防火墙工具,通过它可以轻松封禁 IP。不过,这种方式的缺点是操作繁琐且不灵活。每当需要动态封禁某个 IP 时,我们得手动去操作,不太适合自动化管理。而且,这样的封禁是全局生效的,一旦添加了黑名单中的 IP,它就完全无法访问服务器,除非手动移除。
方法 2:Web 服务器层面的拦截(Nginx + Lua)
这种方法是我们今天的重点,利用 Nginx 的 Lua 模块配合 Redis,可以非常灵活地动态封禁 IP。Nginx 负责处理请求,Lua 脚本在请求到来时判断 IP 是否需要封禁,而 Redis 则用来存储 IP 黑名单和封禁时长。
这个方法的优点是:
动态封禁:我们可以设置一个超时机制,自动解封被封禁的 IP。
分布式管理:通过 Redis 存储黑名单,可以在多台服务器间共享数据,方便管理。
灵活性:可以对封禁策略进行动态调整,甚至支持高级的 IP 限制和行为监控。
缺点是:我们需要了解 Nginx 配置、Lua 脚本编写以及 Redis 的使用。
方法 3:应用层面的拦截(代码实现)
这种方法通过在应用层直接判断 IP 是否在黑名单中来控制访问。实现起来简单直观,但性能不如前两者。每当一个请求到来时,代码会去查询黑名单,这对于高并发场景可能会带来一定的性能压力。
3. Nginx + Lua + Redis 方案实现
接下来,我们深入讲解如何通过 Nginx 配合 Lua 脚本以及 Redis 实现动态 IP 封禁。首先,我们需要确保系统已经安装了 Lua 和 Redis,并且 Nginx 已经配置了 Lua 模块。
Nginx 配置
首先,在 Nginx 配置文件中,我们需要启用 Lua 模块,并且指定 Lua 脚本来处理访问控制。修改 nginx.conf 配置文件,在需要处理请求的 location 块中添加 Lua 脚本调用。
http { lua_shared_dict limit_req_zone 10m; # 用来存放 Redis 连接池 server { listen 80; location / { set $limit 0; access_by_lua_file /etc/nginx/lua/access_limit.lua; # 引用 Lua 脚本 } } }
Lua 脚本实现(access_limit.lua)
接下来我们实现 access_limit.lua 脚本,主要完成以下几个任务:
连接 Redis。
获取请求中的客户端 IP 地址。
判断该 IP 是否在黑名单中。
如果不在黑名单中,则记录访问次数;如果在黑名单中,则拒绝请求。
local redis = require "resty.redis" -- 引入 Redis 库 local red = redis:new() -- 创建 Redis 对象 red:set_timeout(1000) -- 设置连接超时时间为 1 秒 -- 连接到 Redis 服务器 local ok, err = red:connect("127.0.0.1", 6379) if not ok then ngx.log(ngx.ERR, "failed to connect to Redis: ", err) return ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) end -- 获取客户端 IP 地址 local client_ip = ngx.var.remote_addr -- 检查该 IP 是否在黑名单中 local res, err = red:get("blacklist:" .. client_ip) if res == "1" then ngx.log(ngx.ERR, "IP " .. client_ip .. " is blacklisted") return ngx.exit(ngx.HTTP_FORBIDDEN) end -- 如果 IP 不在黑名单中,则统计访问次数 local visits, err = red:get("visits:" .. client_ip) if visits == ngx.null then visits = 0 end visits = visits + 1 -- 如果访问次数超过设定阈值,则加入黑名单 if visits > 10 then -- 设定的阈值为 10 次请求 red:set("blacklist:" .. client_ip, 1) red:expire("blacklist:" .. client_ip, 3600) -- 设置封禁时长为 1 小时 end -- 更新访问次数 red:set("visits:" .. client_ip, visits) red:expire("visits:" .. client_ip, 60) -- 设置过期时间为 1 分钟
这个脚本通过 Redis 存储访问数据并动态判断是否需要封禁 IP。如果某个 IP 在短时间内超过了访问次数限制(比如 10 次),它就会被封禁 1 小时。
Redis 配置与连接
在这段 Lua 脚本中,我们通过 resty.redis 模块连接 Redis 服务器。Redis 在这里充当了一个缓存的角色,用来存储每个 IP 的访问次数和黑名单信息。使用 Redis 的好处是它具有高性能、易于扩展且支持分布式管理。
4. 方案总结
通过 Nginx + Lua + Redis,我们可以高效地实现 IP 封禁策略。这个方案的优点在于:
配置简单,且无需改变业务代码。
适合高并发的场景,对性能影响较小。
支持动态配置,封禁时长可以灵活调整。
Redis 支持分布式管理,可以扩展到多台服务器。
此外,Redis 还可以用于实现更多高级功能,例如 IP 访问频率限制、暴力破解防护等。
5. 扩展与高级功能
除了基本的封禁功能,Nginx + Lua + Redis 还可以扩展为更强大的安全防护系统。例如:
异常检测与自动封禁:通过分析访问日志,检测异常访问模式,自动封禁异常 IP。
白名单机制:对于一些可信的 IP,可以设置白名单,让它们绕过封禁规则。
验证码验证:对频繁访问的 IP 提供验证码验证,进一步阻止恶意访问。
数据统计与分析:记录封禁的数据,通过分析日志来优化封禁策略。
总之,Nginx 与 Lua 脚本的结合,使得动态封禁 IP 成为一个简单而灵活的解决方案,不仅能有效防止恶意访问,还可以根据需要进行扩展与优化。
原文来源:https://mp.weixin.qq.com/s/exNdmfbyX48QoDtdVLdOtQ
来源:本文内容搜集或转自各大网络平台,并已注明来源、出处,如果转载侵犯您的版权或非授权发布,请联系小编,我们会及时审核处理。
声明:江苏教育黄页对文中观点保持中立,对所包含内容的准确性、可靠性或者完整性不提供任何明示或暗示的保证,不对文章观点负责,仅作分享之用,文章版权及插图属于原作者。
Copyright©2013-2024 JSedu114 All Rights Reserved. 江苏教育信息综合发布查询平台保留所有权利
苏公网安备32010402000125 苏ICP备14051488号-3技术支持:南京博盛蓝睿网络科技有限公司
南京思必达教育科技有限公司版权所有 百度统计