Nginx + Lua + Redis:打造智能 IP 黑名单系统

Nginx + Lua + Redis:打造智能 IP 黑名单系统

nginx通过Lua+Redis实现动态封禁IP

需求背景

在Web服务中,为了防止恶意用户或爬虫对服务器造成不必要的负载和潜在的安全威胁,我们可以通过设置动态IP黑名单来拒绝来自这些IP的请求。本文将详细介绍如何使用Nginx配合Lua脚本及Redis数据库实现这一功能,并允许为每个被封禁的IP设定失效时间。

实现方案对比

在实现 IP 黑名单功能时,有多种方案可供选择:

  • 优点:直接在服务器物理层面拦截指定 IP 的网络请求,操作直接且高效。

  • 缺点:需要手动编辑配置文件,操作繁琐且不灵活,难以动态管理。

  • 优点:通过 Nginx 和 Lua 脚本的结合,可动态实现 IP 封禁,并设置封禁时间,实现分布式封禁。

  • 缺点:需要一定的 Lua 脚本和 Nginx 配置知识,但相对容易学习和掌握。

  • 优点:通过编写代码实现 IP 黑名单功能,相对简单且易于维护。

  • 缺点:在高并发情况下可能影响性能,且代码可能会变得冗长。

  1. 操作系统层面(iptables):

  2. Web 服务器层面(Nginx + Lua):

  3. 应用层面:

为了兼顾灵活性和管理便捷性,我们选择通过 Nginx + Lua + Redis 的架构来实现 IP 黑名单功能。

这里选择结合Nginx与Lua脚本并通过Redis存储黑名单数据的方法,以达到灵活管理并共享黑名单的目的。

Nginx与Lua脚本并通过Redis存储黑名单数据的方法

操作步骤

  1. 安装必要的软件确保你的系统已经安装了OpenResty版Nginx以及Redis服务。可以参考官方文档完成相关安装。

  2. 创建Lua脚本文件创建一个名为access_limit.lua的文件,路径根据实际需要调整,例如 /usr/local/lua/access_limit.lua。该脚本负责检查客户端IP是否位于Redis维护的黑名单内,并据此决定是否继续处理请求。

lua脚本具体内容凯哥会放在文末。

配置 Nginx.conf

在 Nginx 配置文件中,我们需要在需要进行限制的 server 的 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; # 加上了这条配置,则会根据 access_limit.lua 的规则进行限流

    alias /usr/local/web/;

    index  index.html index.htm;

}

Lua 脚本实现

在 /usr/local/lua/access_limit.lua 文件中,我们编写 Lua 脚本来实现 IP 黑名单的访问控制。该脚本将从 Redis 中读取黑名单列表,并判断当前请求的 IP 是否在黑名单中。
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 中的黑名单,实现动态管理。

扩展应用场景

  • 防止恶意访问:阻止暴力破解密码、SQL 注入等非法访问。

  • 防止爬虫和数据滥用:减轻服务器负载,保护数据安全。

  • 防止 DDoS 攻击:封禁发起大规模攻击的 IP 地址,保护服务器稳定性。

  • 限制访问频率:防止暴力破解、刷票等恶意行为。

  • 异常检测和自动封禁:通过分析访问日志和行为模式,自动封禁异常行为的 IP。

  • 白名单机制:允许特定 IP 绕过黑名单限制,确保合法用户正常访问。

  • 验证码验证:对频繁访问或异常行为的 IP 进行验证码验证,增强安全性。

  • 数据统计和分析:记录封禁 IP 的次数、持续时间等信息,为后续优化提供依据。

  1. IP 黑名单的实际应用

  2. 高级功能和改进

相关推荐
看山还是山,看水还是。1 小时前
Nginx 的 Http 模块介绍(中)
android·运维·网络·nginx·http
瓜牛_gn2 小时前
redis详细教程(5.AOP和RDB持久化)
数据库·redis·缓存
风吹落叶花飘荡2 小时前
从零开始的 vue项目部署到服务器详细步骤(vue项目build打包+nginx部署+配置ssl证书)
服务器·vue.js·nginx
gorgor在码农2 小时前
Lua 从基础入门到精通(非常详细)
开发语言·lua
~见贤思齐~10 小时前
记一次真实项目的性能问题诊断、优化(阿里云redis分片带宽限制问题)过程
redis·阿里云·云计算·1024程序员节
feilieren12 小时前
Nginx - 缓慢的 HTTP 拒绝服务攻击
java·nginx·1024程序员节
IsToRestart14 小时前
Redis的Key和Value的设计原则有哪些?
数据库·redis·缓存
檀越剑指大厂14 小时前
【Nginx系列】499错误
运维·nginx
丶Darling.15 小时前
尚硅谷 | Nginx | 学习笔记
笔记·学习·nginx·尚硅谷
book012115 小时前
提升 Nginx 安全性:隐藏 Server 信息的最佳实践
linux·运维·nginx·网络安全