环境准备
linux version: centos7 / ubuntu 等
redis version: 5.0.5
nginx version: nginx-openresty
设计方案
实现 ip 黑名单的功能有很多途径:
1、在操作系统层面,配置 iptables,来拦截指定 ip 的网络请求。
优点:简单直接,在服务器物理层面上进行拦截
缺点:每次需要手动上服务器修改配置文件,操作繁琐且不灵活
2、在 web 服务器层面,通过 nginx 自身的 deny 选项或者 lua 插件配置 ip 黑名单。
优点:可动态实现封禁 ip,通过设置封禁时间可以做到分布式封禁
缺点:需要了解 lua 脚本和 nginx 配置,有一定的学习成本
3、在应用层面,在处理请求之前检查客户端的 ip 地址是否在黑名单中。
优点:通过编写代码来实现,相对简单且易于维护。
缺点:代码可能会变得冗长,而且在高并发情况下可能影响性能。
为了方便管理和共享黑名单,通过 nginx + lua + redis 的架构实现 ip 黑名单的功能
配置 nginx.conf
在需要进行限制的 server 的 location 中添加如下配置:
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; # 加上了这条配置,则会根据 access_limit.lua 的规则进行限流
alias /usr/local/web/;
index index.html index.htm;
} 配置 lua 脚本
/usr/local/lua/access_limit.lua
-- 可以实现自动将访问频次过高的ip地址加入黑名单封禁一段时间
--连接池超时回收毫秒
local pool_max_idle_time = 10000
--连接池大小
local pool_size = 100
--redis 连接超时时间
local redis_connection_timeout = 100
--redis host
local redis_host = "your redis host ip"
--redis port
local redis_port = "your redis port"
--redis auth
local redis_auth = "your redis authpassword";
--封禁ip时间(秒)
local ip_block_time= 120
--指定ip访问频率时间段(秒)
local ip_time_out = 1
--指定ip访问频率计数最大值(次)
local ip_max_count = 3
-- 错误日志记录
local function errlog(msg, ex)
ngx.log(ngx.err, msg, ex)
end
-- 释放连接池
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 connct 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)
end
--设置超时时间
client:set_timeout(redis_connection_timeout)
-- 优化验证密码操作 代表连接在连接池使用的次数,如果为0代表未使用,不为0代表复用 在只有为0时才进行密码校验
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 cliendip = getip();
local incrkey = "limit:count:"..cliendip
local blockkey = "limit:block:"..cliendip
--查询ip是否被禁止访问,如果存在则返回403错误代码
local is_block,err = client:get(blockkey)
if tonumber(is_block) == 1 then
ngx.exit(ngx.http_forbidden)
close_redis(client)
end
local ip_count, err = client:incr(incrkey)
if tonumber(ip_count) == 1 then
client:expire(incrkey,ip_time_out)
end
--如果超过单位时间限制的访问次数,则添加限制访问标识,限制时间为ip_block_time
if tonumber(ip_count) > tonumber(ip_max_count) then
client:set(blockkey,1)
client:expire(blockkey,ip_block_time)
end
close_redis(client) 总结
以上,便是 nginx+lua+redis 实现的 ip 黑名单功能,具有如下优点:
配置简单轻量,对服务器性能影响小。
多台服务器可以通过共享 redis 实例共享黑名单。
动态配置,可以手工或者通过某种自动化的方式设置 redis 中的黑名单
扩展
1、ip 黑名单的应用场景
ip 黑名单在实际应用中具有广泛的应用场景,主要用于保护服务器和应用免受恶意攻击、爬虫或滥用行为的影响。下面列举几个常见的应用场景:
防止恶意访问: 黑名单可以阻止那些试图通过暴力破 解密码、sql 注入、xss 攻击等方式进行非法访问的 ip 地址。
防止爬虫和数据滥用: 黑名单可以限制那些频繁访问网站并抓取大量数据的爬虫,以减轻服务器负载和保护数据安全。
防止 ddos 攻击: 黑名单可以封禁那些发起大规模ddos攻击的ip地址,保护服务器的稳定性和安全性。
限制访问频率: 黑名单可以限制某个ip在特定时间段内的访问次数,防止恶意用户进行暴力破 解、刷票等行为。
2、高级功能和改进
除了基本的 ip 黑名单功能外,还可以进行一些高级功能和改进,以提升安全性和用户体验:
异常检测和自动封禁: 通过分析访问日志和行为模式,可以实现异常检测功能,并自动将异常行为的 ip 地址封禁,提高安全性。
白名单机制: 除了黑名单,还可以引入白名单机制,允许某些 ip 地址绕过黑名单限制,确保合法用户的正常访问。
验证码验证: 对于频繁访问或异常行为的 ip,可以要求其进行验证码验证,以进一步防止恶意行为。
数据统计和分析: 将黑名单相关的数据进行统计和分析,例如记录封禁 ip 的次数、持续时间等信息,以便后续优化和调整策略。
通过不断改进和优化 ip 黑名单功能,可以更好地保护服务器和应用的安全。
到此这篇关于nginx实现动态封禁ip的设计方案的文章就介绍到这了,更多相关nginx动态封禁ip内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论