Nginx Openresty通过Lua+Redis 实现动态封禁IP
需求
为了封禁某些爬虫或者恶意用户对服务器的请求,我们需要建立一个动态的 IP 黑名单。对于黑名单中的 IP ,我们将拒绝提供服务。并且可以设置封禁失效时间
环境准备
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 thenreturnendlocal ok, err = red:set_keepalive(pool_max_idle_time, pool_size)if not ok thenngx.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 thenclose_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 thenlocal ok, err = client:auth(redis_auth)if not ok thenerrlog("failed to auth: ", err)returnend--从连接池中获取连接,无需再次认证密码
elseif err thenerrlog("failed to get reused times: ", err)return
end-- 获取请求ip
local function getIp()local clientIP = ngx.req.get_headers()["X-Real-IP"]if clientIP == nil thenclientIP = ngx.req.get_headers()["x_forwarded_for"]endif clientIP == nil thenclientIP = ngx.var.remote_addrendreturn clientIP
endlocal 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 thenngx.exit(ngx.HTTP_FORBIDDEN)close_redis(client)
endlocal ip_count, err = client:incr(incrKey)
if tonumber(ip_count) == 1 thenclient:expire(incrKey,ip_time_out)
end
--如果超过单位时间限制的访问次数,则添加限制访问标识,限制时间为ip_block_time
if tonumber(ip_count) > tonumber(ip_max_count) thenclient:set(blockKey,1)client:expire(blockKey,ip_block_time)
endclose_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 Openresty通过Lua+Redis 实现动态封禁IP
需求 为了封禁某些爬虫或者恶意用户对服务器的请求,我们需要建立一个动态的 IP 黑名单。对于黑名单中的 IP ,我们将拒绝提供服务。并且可以设置封禁失效时间 环境准备 linux version: centos7 / ubuntu 等 redis version: 5.0.5 nginx version: nginx…...
.Net 字符集与编解码
0 .NET 字符集编解码 .Net 内部使用的字符集是Unicode,如果需要编码为其他诸如GBK、UTF8编码,可以通过Encoding 类来实现。 using System.Text;void PrintBytes(byte[] bytes) {foreach (var b in bytes){Console.Write("{0:X} ", b);}Conso…...
Spinnaker 基于 jenkins 触发部署
jenkins job 触发部署 将 Jenkins 设置为 Spinnaker 中的持续集成 (CI) 系统可让您使用 Jenkins 触发管道、向管道添加 Jenkins 阶段或向管道添加脚本阶段。 前置要求: 已在kubernetes中部署spinnaker已准备可用的jenkins实例 启用 jenkins触发器 官方文档&…...
FLASK博客系列6——数据库之谜
我们上一篇已经实现了简易博客界面,你还记得我们的博客数据是自己手动写的吗?但实际应用中,我们是不可能这样做的。大部分程序都需要保存数据,所以不可避免要使用数据库。我们这里为了简单方便快捷,使用了超级经典的SQ…...
Clickhouse UPDATE 和 DELETE操作
历史: 在OLAP数据库中,可变数据(Mutable data)通常是不被欢迎的,Clickhouse也是如此,早期版本不支持UPDATE和DELTE操作。在Clickhouse 1.1.54388版本之后才支持UPDATE和DELETE操作,适用于Merge…...
golang channel执行原理与代码分析
使用的go版本为 go1.21.2 首先我们写一个简单的chan调度代码 package mainimport "fmt"func main() {ch : make(chan struct{})go func() {ch <- struct{}{}ch <- struct{}{}}()fmt.Println("xiaochuan", <-ch)data, ok : <-chfmt.Println(&…...
OpenCvSharp从入门到实践-(04)色彩空间
目录 1、GRAY色彩空间 2、从BGR色彩空间转换到GRAY色彩空间 2.1色彩空间转换码 2.2实例 BGR色彩空间转换到GRAY色彩空间 3、HSV色彩空间 4、从BGR色彩空间转换到HSV色彩空间 4.1色彩空间转换码 4.2实例 BGR色彩空间转换到HSV色彩空间 1、GRAY色彩空间 GRAY色彩空间通常…...
100.有序数组的平方(力扣)
代码解决一 class Solution { public:// 函数接受一个整数数组,返回每个元素平方值排序后的结果vector<int> sortedSquares(vector<int>& nums) {int len nums.size(); // 获取数组的长度vector<int> v; // 创建一个新的数组,用…...
微服务--01--简介、服务拆分原则
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 微服务微服务架构,是服务化思想指导下的一套最佳实践架构方案。服务化,就是把单体架构中的功能模块拆分为多个独立项目。 单体架构微服务架构…...
IntelliJ IDEA安装使用教程
IntelliJ IDEA是一个流行的Java 集成开发环境(IDE),由JetBrains公司开发。它是一款全功能的IDE,支持多种编程语言,如Java、Kotlin、Groovy、Scala、Python、JavaScript、HTML、CSS等等。IntelliJ IDEA 提供了高效的代码…...
校园门禁可视化系统解决方案
随着科技的持续进步,数字化校园在教育领域中的地位日益上升,各种智能门禁、安防摄像头等已遍布校园各个地方,为师生提供安全便捷的通行体验。然而数据收集分散、缺乏管理、分析困难等问题也逐渐出现,在这个数字化环境中࿰…...
rest_framework_django学习笔记一(序列化器)
rest_framework_django学习笔记一(序列化器) 一、引入Django Rest Framework 1、安装 pip install djangorestframework2、引入 INSTALLED_APPS [...rest_framework, ]3、原始RESTful接口写法 models.py from django.db import models 测试数据 仅供参考 INSERT INTO de…...
面试题:什么是负载均衡?常见的负载均衡策略有哪些?
文章目录 一、负载均衡二、负载均衡模型分类三、CDN负载均衡四、LVS负载均衡4.1 LVS 支持的三种模式4.1.1 DR 模式4.1.2 TUN 模式4.1.3 NAT 模式 4.2 LVS 基于 Netfilter 的框架实现 五、负载均衡策略是什么六、常用负载均衡策略图解6.1 轮询6.2 加权轮询6.3 最少连接数6.4 最快…...
精通Git(第2版)读书笔记
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言第 1章 入门 11.1 关于版本控制 11.1.1 本地版本控制系统 1 第 2章 Git基础 132.1 获取Git仓库 132.1.1 在现有中初始化Git仓库 132.1.2 克隆现有仓库 14 2.2 在…...
XUbuntu22.04之OBS30.0设置录制音频降噪(一百九十六)
简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒…...
渗透测试学习day4
文章目录 靶机:SequelTask1Task2Task3Task4Task5Task6Task7Task8 靶机:CrocodileTask1Task2Task3Task4Task5Task6Task7Task8Task9Task10 靶机:ResponderTask1Task2Task3Task4Task5Task6Task7Task8Task9Task10Task11 靶机:ThreeTas…...
Deepin使用记录-deepin系统下安装RabbitMq
目录 0、引言 1、由于RabbitMq是erlang语言开发的,所有需要先安装erlang 2、更新源并安装RabbitMq 3、安装完成之后,服务是启动的,可以通过以下语句查看状态 4、这样安装完成之后,是看不到web页面的,需要再安装一…...
【腾讯云云上实验室】用向量数据库——实现高效文本检索功能
文章目录 前言Tencent Cloud VectorDB 简介Tencent Cloud VectorDB 使用实战申请腾讯云向量数据库腾讯云向量数据库使用步骤腾讯云向量数据库实现文本检索 结论和建议 前言 想必各位开发者一定使用过关系型数据库MySQL去存储我们的项目的数据,也有部分人使用过非关…...
Pytorch中的gather的理解和用法
Pytorch中的gather的理解和用法 这个Gather的用法花费了点时间,我相信很多人一开始不太懂。 跟着我简单理解。 首先样例是: tensor([[ 3, 4, 5],[ 6, 7, 8],[ 9, 10, 11]])然后index: [[2, 1, 0]]然后执行的代码: tensor_0.gather(0…...
唯创知音WTN6系列语音芯片:高音频采样率与精细音量控制赋能广泛应用
在语音芯片领域,唯创知音的WTN6系列语音芯片以其出色的性能和广泛的应用领域,无疑是行业的一颗璀璨明星。近期,该系列芯片实现了音频采样率32kHz的突破,以及16级音量控制的精细调节,进一步提升了其在各类应用中的表现。…...
使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...
React Native 开发环境搭建(全平台详解)
React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...
CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...
Python爬虫(二):爬虫完整流程
爬虫完整流程详解(7大核心步骤实战技巧) 一、爬虫完整工作流程 以下是爬虫开发的完整流程,我将结合具体技术点和实战经验展开说明: 1. 目标分析与前期准备 网站技术分析: 使用浏览器开发者工具(F12&…...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...
【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】
1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...
使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的“no matching...“系列算法协商失败问题
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的"no matching..."系列算法协商失败问题 摘要: 近期,在使用较新版本的OpenSSH客户端连接老旧SSH服务器时,会遇到 "no matching key exchange method found", "n…...
作为测试我们应该关注redis哪些方面
1、功能测试 数据结构操作:验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化:测试aof和aof持久化机制,确保数据在开启后正确恢复。 事务:检查事务的原子性和回滚机制。 发布订阅:确保消息正确传递。 2、性…...
Vite中定义@软链接
在webpack中可以直接通过符号表示src路径,但是vite中默认不可以。 如何实现: vite中提供了resolve.alias:通过别名在指向一个具体的路径 在vite.config.js中 import { join } from pathexport default defineConfig({plugins: [vue()],//…...
