redis不支持subscribe限频,崩溃主因是输出缓冲区溢出;需通过client-output-buffer-limit、bind、requirepass和命令重命名组合防御,并禁用psubscribe及notify-keyspace-events。

Redis 本身不提供订阅频率限制机制,无法直接“限频”;所谓“防止恶意订阅导致崩溃”,核心是堵住滥用入口、收紧连接资源、避免缓冲区溢出——不是靠 rate limiting,而是靠 client-output-buffer-limit、bind、requirepass 和命令重命名组合防御。
为什么 SUBSCRIBE 本身不会被限流,但容易引发崩溃
Redis 的 SUBSCRIBE 命令是无状态的轻量操作,服务端不校验订阅者身份或频次。问题不出在“订阅动作”,而出在后续持续接收消息时的输出缓冲区堆积:
- 每个 Pub/Sub 客户端独占一个输出缓冲区,默认硬限制为
8MB,软限制为“60 秒内持续超过2MB” —— 超限即断连 - 攻击者可起成百上千个连接反复
SUBSCRIBE到高频频道(如tmp_*),再故意不读消息,快速耗尽 Redis 内存或触发连接风暴 - 若未设
bind或requirepass,外部 IP 可直连并批量建连,进一步放大风险
必须修改的 redis.conf 关键配置项
以下配置需同时生效,缺一不可:
-
bind 127.0.0.1或内网固定 IP(如bind 10.0.1.5),绝不可留空或写0.0.0.0 -
requirepass your_strong_password,密码不得出现在前端代码或公开配置中 -
rename-command SUBSCRIBE ""(彻底禁用)或rename-command SUBSCRIBE "safe_subscribe"(仅限可信服务调用别名) -
client-output-buffer-limit pubsub 4mb 2mb 60:比默认更激进(原为8mb 2mb 60),加快异常连接淘汰
如何识别并清理已存在的恶意订阅连接
不能等崩溃才响应,要主动扫描:
- 用
CLIENT LIST TYPE pubsub查当前所有订阅连接,重点关注omem(输出缓冲区内存)值 > 1MB 的连接 - 结合
CLIENT KILL TYPE pubsub清理高缓冲连接(注意:这会中断消费者,需配合下游重连逻辑) - 定期跑脚本查异常频道:
PUBSUB CHANNELS "tmp_*"+SCAN 0 MATCH "tmp_*" COUNT 1000,确认是否真有数据堆积而非空频道占位 - 发现恶意频道后,不再向其
PUBLISH,等待最后订阅者退订,频道自动消失(Redis 不存空频道)
容易被忽略的底层细节
很多人以为关掉 SUBSCRIBE 就万事大吉,其实还有两个隐性通道:
-
PSUBSCRIBE是独立命令,也要同样重命名(rename-command PSUBSCRIBE "") -
notify-keyspace-events开启后,Redis 会自动向__keyspace@0__:xxx这类内部频道发事件——若业务没关这个功能,攻击者可通过监听这些频道实现“免 SUBSCRIBE 的被动订阅”,所以应设为notify-keyspace-events ""彻底关闭











