1、简述
在日常的生产环境中,网站可能会遭遇恶意请求、ddos 攻击或其他有害的访问行为。为了应对这些情况,动态封禁 ip 是一项十分重要的安全策略。本篇博客将介绍如何通过 nginx 实现动态封禁 ip,从配置到自动化的实现步骤。
2、实现方式
nginx 本身支持简单的基于 ip 的访问控制(如 deny 和 allow 指令),但要实现动态封禁,通常结合以下几种方案:
- fail2ban:一个常用的自动封禁工具,通过监控日志发现恶意行为并自动修改 nginx 配置文件。
- nginx 动态模块:如 ngx_http_limit_req_module 和 ngx_http_limit_conn_module,用于限制请求频率和并发数,结合脚本实现 ip 封禁。
- 基于 redis 或数据库的方案:可以通过 lua 脚本或第三方模块,从 redis 或 mysql 等存储中动态加载封禁的 ip 列表。
3、使用 fail2ban 动态封禁
fail2ban 是一种常见的动态封禁工具,通过监控日志文件中的恶意行为自动更新 nginx 配置。下面是通过 fail2ban 实现动态封禁的步骤。
3.1 安装 fail2ban
sudo apt-get update sudo apt-get install fail2ban
3.2 配置 nginx 日志
确保 nginx 配置中的日志能记录恶意请求。以下是一个简单的日志配置:
http { log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; }
3.3 配置 fail2ban 规则
创建 nginx 的过滤规则,编辑 /etc/fail2ban/filter.d/nginx-http-auth.conf,加入以下规则来匹配日志中的恶意行为:
[definition] failregex = ^<host> -.*"(get|post).*http/.*".* 403 ignoreregex =
3.4 设置 fail2ban 的 jail 配置
在 /etc/fail2ban/jail.local 文件中,增加对 nginx 的监控配置:
[nginx-http-auth] enabled = true port = http,https filter = nginx-http-auth logpath = /var/log/nginx/access.log maxretry = 5
- logpath:指向 nginx 的日志文件。
- maxretry:设置多少次失败后封禁 ip。
3.5 启动 fail2ban
sudo service fail2ban restart
这样,当某个 ip 连续访问 5 次 403 页面时,它将被自动封禁。
4、使用 nginx 的 limit 模块动态限制
nginx 自带的 ngx_http_limit_req_module 和 ngx_http_limit_conn_module 可以用于动态限制请求。通过设置请求频率和并发连接数,可以有效抵御恶意爬虫和 ddos 攻击。
4.1 配置请求频率限制
在 nginx 配置中加入以下代码来限制每个 ip 的请求频率:
http { limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s; server { location / { limit_req zone=one burst=5; } } }
- limit_req_zone:定义一个共享内存区域,用于记录请求速率。
- rate=1r/s:每个 ip 限制为每秒最多 1 次请求。
4.2 动态调整限制
要用 redis 和 lua 实现动态封禁恶意 ip 的功能,可以借助 redis 的计数和过期特性。在 redis 中,可以用 lua 脚本来动态检测某个 ip 的请求频率,一旦超过设定的阈值,就对该 ip 进行封禁。
以下是一个 lua 脚本的样例,用于封禁恶意 ip。假设我们会在 redis 中记录每个 ip 的请求次数,并在达到限制后进行封禁。以下 lua 脚本实现了上述逻辑,设定了一个限制:ip 在 60 秒内请求 10 次以上会触发封禁,封禁持续 3600 秒(1 小时):
-- lua 脚本实现动态封禁恶意ip local ip = keys[1] -- 传入的 ip 地址 local max_requests = tonumber(argv[1]) -- 最大请求次数 local ban_time = tonumber(argv[2]) -- 封禁持续时间 local expire_time = tonumber(argv[3]) -- ip 计数的过期时间 -- 构建 redis 键 local ip_key = "ip:" .. ip local ban_key = "ban:" .. ip -- 检查 ip 是否已封禁 if redis.call("exists", ban_key) == 1 then return {false, "ip 已封禁"} end -- 增加 ip 请求计数 local count = redis.call("incr", ip_key) -- 如果是首次请求,设置请求计数的过期时间 if count == 1 then redis.call("expire", ip_key, expire_time) end -- 检查请求次数是否超过最大请求限制 if count > max_requests then -- 达到限制,封禁 ip 并设置封禁时间 redis.call("set", ban_key, "1") redis.call("expire", ban_key, ban_time) return {false, "已达请求限制,ip 已封禁"} end -- 如果请求未超限,返回当前请求计数 return {true, count}
要在 redis 中执行这个 lua 脚本,你可以通过 redis 客户端执行 eval 命令。假设 ip 地址是 192.168.0.1,请求限制为 10 次,封禁时间为 3600 秒,计数过期时间为 60 秒:
eval "<lua_script>" 2 192.168.0.1 10 3600 60
5、总结
通过以上方法,可以实现 nginx 下的动态封禁 ip,从而有效保护网站免受恶意攻击。在实际应用中,可以根据需求选择 fail2ban 或 nginx 自带的模块,甚至结合数据库方案实现更复杂的动态封禁机制。
这篇博客为初学者提供了 nginx 实现动态封禁 ip 的思路和具体配置示例。你可以根据业务场景灵活调整参数,提升系统安全性。
到此这篇关于nginx实现动态封禁ip的步骤指南的文章就介绍到这了,更多相关nginx动态封禁ip内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论