Redis PUBLISH无频道级权限控制,ACL和rename-command均无法阻止恶意发布;需通过TLS加密、前置网关白名单校验、消息签名加密三重防护。

根本防不住——Redis 的 PUBLISH 命令没有频道级写权限控制,ACL 不支持按频道名限制发布行为,rename-command 也纯属心理安慰。
为什么 ACL + rename-command 对防止刷脏数据完全无效
Redis ACL 只能控制用户能否执行 PUBLISH 命令,不能指定“只允许向 app:notify 发布”。哪怕你配置了 ~app:* +publish,该模式匹配在 Redis 中仅对 key 生效,对 Pub/Sub channel 完全不解析。重命名 PUBLISH 为 safe_publish 后,攻击者只要知道新命令名,照样能调用;SUBSCRIBE 端更不受影响,照样收得到脏消息。
- ACL 中的
~pattern语法只作用于 key 空间(如 SET/GET),Pub/Sub 频道名不参与 ACL 匹配 -
rename-command PUBLISH只改命令名,不改变权限模型,也不影响协议层语义 - 只要客户端通过认证、连接建立,就能向任意频道发消息,包括
__test__、system:cmd这类明显恶意前缀
真正能落地的三道防线
必须放弃“靠 Redis 自身拦住发布”的幻想,转而从传输、接入、内容三端设防:
- 强制 TLS:服务端启用
tls-port,客户端只允许用rediss://协议连接;关闭明文port 6379(防火墙 DROP 或注释掉),否则中间人可劫持并伪造PUBLISH - 前置网关校验:在业务服务与 Redis 之间加一层代理(如 Envoy 或自研 Go 网关),对所有出向
PUBLISH请求做频道白名单检查,例如只放行^app:[a-z]+:[a-z]+$,非法频道直接 403 拒绝 - 消息体签名+加密:发布前用业务私钥对 payload 做 HMAC-SHA256 签名,并 AES-GCM 加密;订阅端收到后先验签再解密,丢弃无签名或验签失败的消息——这能防篡改,也能让脏数据即使进了频道也毫无意义
别碰 Lua 脚本拦截发布行为
有人想在服务端用 EVAL 拦截 PUBLISH,但 Redis 明确禁止在 SUBSCRIBE 上下文中执行 Lua(EVAL 在 pub/sub client 中被禁用),且 PUBLISH 本身是原子命令,无法被 Lua 中间拦截。试图用 CONFIG SET notify-keyspace-events 监听事件再反向阻断,既延迟高又不可靠,还可能引发循环触发。
-
EVAL在已订阅的客户端中直接报错:ERR Error running script (call to f_...): @user_script:1: @enable-write-commands-in-subscribe-mode - keyspace 事件监听是异步的,
PUBLISH已完成才触发,此时脏数据早已广播出去 - 任何基于事件回调的“事后拉黑”都晚了,订阅端已收到,无法撤回
最常被忽略的一点:频道名本身不是安全边界。你无法阻止别人往 app:notify 发送 {"cmd":"rm -rf /"},只能确保接收方根本不信这个 payload——所以签名验证和结构校验必须在应用层做死,不能依赖 Redis 代劳。


















