怎样利用Redis实现接口防刷限制恶意穿透查询_固定窗口与滑动窗口

P粉602998670

P粉602998670

2026-07-10

716人浏览

原创

滑动窗口是防刷的底线选择,因固定窗口易被边界请求穿透;必须用zset+lua实现精确时间窗口统计,并正确识别真实客户端ip。

怎样利用redis实现接口防刷限制恶意穿透查询_固定窗口与滑动窗口

固定窗口限流容易被恶意穿透,滑动窗口才是防刷的底线选择——不是“更好”,而是“必须”。

固定窗口为什么挡不住恶意穿透

固定窗口本质是按整点切片(比如每分钟重置),攻击者只要卡在窗口边界发请求,就能绕过限制。典型现象是:12:00:59.999 发 100 次,12:01:00.001 再发 100 次,两次都通过,但真实时间只隔了 2 毫秒。

常见错误做法包括:

  • INCR + EXPIRE 按分钟拼 key,如 limit:ip:192.168.1.1:202605261201
  • 没做 key 命名隔离,多个 IP 共用一个计数器
  • 窗口时间设为 60 秒,但没校验当前时间戳是否落在该窗口内,仅靠 key 过期兜底

这些都会导致:单 IP 瞬时 QPS 翻倍、日志里看不到超限记录、监控曲线出现尖峰但限流不生效。

滑动窗口必须用 ZSET,不能用 INCR 或 HASH

滑动窗口的核心是“任意时刻往前推 N 秒”的精确统计,这要求保留原始请求时间戳。Redis 的 ZSET 是唯一能同时满足排序、范围删除、去重和原子操作的数据结构。

正确做法要点:

  • key 设计为 limit:ip:{ip},避免拼时间戳分片
  • 每次请求执行原子 Lua 脚本,包含三步:ZREMRANGEBYSCORE 清旧、ZCARD 统计、ZADD 记新
  • score 必须用秒级或毫秒级时间戳(推荐毫秒,避免同一秒多请求冲突)
  • 必须调用 EXPIRE 设置 key 过期(建议设为窗口时长 × 2,如 120 秒),否则内存持续增长

示例 Lua 脚本片段(供参考):

Redis 8.2.3
Redis 8.2.3

Redis 8.2.3 是一款安全优先的高性能键值存储系统。该版本紧急修复了可能引发远程代码执行(RCE)的高危漏洞(CVE-2025-62507),并解决了 HyperLogLog 及 Cuckoo Filter 等数据结构在特定场景下的崩溃问题。建议所有用户立即升级,以保障生产环境的系统稳定与数据安全。

下载
local key = KEYS[1]
local now = tonumber(ARGV[1])
local window = tonumber(ARGV[2])
local limit = tonumber(ARGV[3])
redis.call('ZREMRANGEBYSCORE', key, 0, now - window)
local count = redis.call('ZCARD', key)
if count <h3>IP 维度限流要注意真实客户端识别</h3><p>直接取 <code>request.client.host</code> 在反向代理后大概率拿到的是 Nginx 或 Cloudflare 的 IP,不是真实用户 IP。</p><p>必须检查以下 header 顺序并取第一个有效值:</p>
  • X-Forwarded-For(注意可能被伪造,需配合白名单或可信代理配置)
  • X-Real-IP(Nginx 默认设置,更可靠)
  • CF-Connecting-IP(Cloudflare 场景下必须启用)

FastAPI 示例中不要写 request.client.host,改用:

client_ip = request.headers.get("X-Real-IP") or \
             request.headers.get("X-Forwarded-For", "").split(",")[0].strip() or \
             request.client.host

漏掉这一步,限流会全部作用在网关 IP 上,完全失效。

滑动窗口的性能开销比你想象中低,但得避开几个坑

ZSET 操作本身很快,真正拖慢的是网络往返和脚本执行逻辑。高频场景下容易踩的坑:

  • 没用连接池,每次新建 Redis 连接 —— 改用 redis-pyConnectionPool
  • Lua 脚本里做了非 Redis 操作(比如时间计算用 os.time())—— 全部移到应用层传入 ARGV
  • 对每个请求都调用 ZCARD 后再判断,其实 ZCOUNT 更直接(ZCOUNT key min max
  • 没设置合理的 timeoutsocket_timeout,超时等待阻塞主线程

滑动窗口真正的复杂点不在实现,而在于它强制你面对两个现实:一是必须处理真实 IP 识别链路,二是必须接受 Lua 脚本作为原子性保障——想绕开它,就只能退回到固定窗口,然后接受被穿透的风险。

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

redis

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

2023.10.19

2768

3

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

2025.10.17

2123

12

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2025.12.29

3357

9

java接口相关教程
java接口相关教程

本专题整合了java接口相关内容,阅读专题下面的文章了解更多详细内容。

2026.01.19

160

15

常用的数据库软件
常用的数据库软件

常用的数据库软件有MySQL、Oracle、SQL Server、PostgreSQL、MongoDB、Redis、Cassandra、Hadoop、Spark和Amazon DynamoDB。更多关于数据库软件的内容详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.02

1906

19

内存数据库有哪些
内存数据库有哪些

内存数据库有Redis、Memcached、Apache Ignite、VoltDB、TimesTen、H2 Database、Aerospike、Oracle TimesTen In-Memory Database、SAP HANA和ache Cassandra。更多关于内存数据库相关问题,详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.14

1579

11

mongodb和redis哪个读取速度快
mongodb和redis哪个读取速度快

redis 的读取速度比 mongodb 更快。原因包括:1. redis 使用简单的键值存储,而 mongodb 存储 json 格式的数据,需要解析和反序列化。2. redis 使用哈希表快速查找数据,而 mongodb 使用 b-tree 索引。因此,redis 在需要高性能读取操作的应用程序中是一个更好的选择。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.02

2473

6

redis怎么做缓存服务器
redis怎么做缓存服务器

redis 作为缓存服务器的答案:redis 是一款开源、高性能、分布式的键值存储,可作为缓存服务器使用。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.07

518

6

redis怎么解决数据一致性
redis怎么解决数据一致性

redis 提供了两种一致性模型,以维护副本数据一致性:强一致性 (sync) 确保写操作仅在复制到所有从节点后才完成;最终一致性 (async) 则在主节点上写操作后认为已完成,牺牲一致性换取性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.07

525

6

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
phpEnv手册
phpEnv手册

共0课时 | 0人学习

进程与SOCKET
进程与SOCKET

共6课时 | 0.5万人学习

Redis+MySQL数据库面试教程
Redis+MySQL数据库面试教程

共72课时 | 9万人学习