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级音量控制的精细调节,进一步提升了其在各类应用中的表现。…...

机器人分类
从发展阶段分类: 1第一代机器人2第二代机器人3第三代机器人:智能型机器人。生于90年代。具有传感器,以前的机器人都不具有传感器 从控制方式分类:(我觉得这个分类好乱) 操作型机器人:可自动控…...

html/css中位置position的绝对位置absolute顺时针盒子案例图片排序
目标图片: Dreamweaver界面: 代码部分: <!doctype html> <html> <head> <meta charset"utf-8"> <title>无标题文档</title> <style type"text/css">.red{background-color:r…...

分享86个清新唯美PPT,总有一款适合您
分享86个清新唯美PPT,总有一款适合您 86个清新唯美PPT下载链接:https://pan.baidu.com/s/1QEaXeWAekCbAWDD0iTgvMw?pwd8888 提取码:8888 Python采集代码下载链接:采集代码.zip - 蓝奏云 学习知识费力气,收集整…...

虚拟机系列:Oracle VM VirtualBox安装/更新/卸载出现 无法访问你试图使用的功能所在的网络位置
Oracle VM VirtualBox安装/更新/卸载出现 无法访问你试图使用的功能所在的网络位置 Oracle VM VirtualBox安装/更新/卸载出现 无法访问你试图使用的功能所在的网络位置Oracle VM VirtualBox安装/更新/卸载出现 无法访问你试图使用的功能所在的网络位置 在更新Oracle VM Virtua…...

【数据库】数据库并发控制的冲突检测,冲突可串行化的调度,保障事务的特性
冲突可串行化 专栏内容: 手写数据库toadb 本专栏主要介绍如何从零开发,开发的步骤,以及开发过程中的涉及的原理,遇到的问题等,让大家能跟上并且可以一起开发,让每个需要的人成为参与者。 本专栏会定期更新…...

java 对象大小计算
说明: 对于64位机:一个对象由三部分组成 对象头(object header) mark word :64bitkclass pointer :32bit(默认使用指针压缩),如果取消指针压缩( XX:-UseCompressedOops),则占用64bit数组长度:数…...

12个国外电子元器件基本参数(下)
DAC8162SDSCR TI DAC088S085CISQNOPB TI TL4050C41QDBZR TI NE3516S02-T1D-A RENESAS TECHNOLOGY MXL862-AL-R MAXLINEAR SI32176-B-GM1R SILICON LAB...

Docker容器中的OpenCV:轻松构建可移植的计算机视觉环境
前言 「作者主页」:雪碧有白泡泡 「个人网站」:雪碧的个人网站 构建可移植的计算机视觉环境 文章目录 前言引言简介:目的和重要性: 深入理解Docker和OpenCVDocker的基本概念和优势:OpenCV简介和应用领域:…...

SSH基础和高级用法
SSH基础和高级用法 SSH(Secure Shell)是一种安全协议,用于在不安全的网络上提供安全的远程登录和数据传输。以下是一些SSH的用法和高级用法: 基本用法: 远程登录:使用ssh命令可以实现在本地计算机上远程…...

算法通关第十三关-青铜挑战数学基础问题
数组元素积的符号 描述 : 已知函数 signFunc(x) 将会根据 x 的正负返回特定值: 如果 x 是正数,返回 1 。如果 x 是负数,返回 -1 。如果 x 是等于 0 ,返回 0 。 给你一个整数数组 nums 。令 product 为数组 nums 中所有元素值的…...