redis pub/sub 本身无法防止敏感信息泄露,因其不加密、无频道级权限控制,必须依赖tls传输、acl用户隔离、应用层前缀校验和实例网络策略四重防护。

不能靠 Redis Pub/Sub 本身传递敏感信息——它不加密、无频道权限、消息明文可见,必须叠加四层防护才可能勉强可控。
为什么 SUBSCRIBE 后立刻能收到所有频道消息
Redis 的 SUBSCRIBE 是“全通”行为:只要认证通过、连接建立,客户端就能收到实例上任意频道的全部消息。ACL 不支持 ~order:notify 这类频道匹配,~* 只作用于 key,对 channel 完全无效。常见误操作是配置了 ACL SETUSER alice on >p@ssw0rd ~* +subscribe 就以为安全了,其实等于开放全部频道订阅权。
真正起作用的只有三件事:
- 服务端启用 TLS(用
rediss://协议,禁用非 TLS 端口) - 应用层做频道前缀白名单校验(如只允许订阅
app:notify:开头的频道) - 消息体在发布前由业务侧 AES 加密,密钥不走 Redis,走 KMS 或环境变量注入
rename-command PUBLISH 根本防不住未授权发布
把 PUBLISH 改成 safe_publish 只是改个名字,不改变权限逻辑。攻击者只要连上、通过认证,就能调用新命令名发消息;订阅端更不受影响——SUBSCRIBE 和频道内容完全不受 rename 影响。
有效做法是:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 用
rename-command PUBLISH ""彻底禁用该命令(适合只读订阅场景) - 或配合 ACL 创建专用用户:
ACL SETUSER pubuser on >mypass ~channel:order:* +publish - 同时确保
bind只监听内网地址,如bind 192.168.10.0/24,并用防火墙 DROP 外网 6379/6380
TLS 配置漏掉一个环节就等于没开
Redis 启用 TLS 不只是加几行配置那么简单。必须同时满足:
- 服务端编译时含 OpenSSL 支持(检查
redis-server --version输出带ssl) -
redis.conf中启用tls-port 6380,且显式指定tls-cert-file、tls-key-file、tls-ca-cert-file - 客户端必须用
rediss://(不是redis://),并传入 CA 证书;自签名证书需设ssl_cert_reqs=None(Python redis-py)或等效参数 - 注释掉或删除原
port 6379行,否则攻击者会降级到明文连接
只要其中一环缺失,抓包工具在宿主机或云平台交换机上就能直接看到频道名和完整消息体。
订阅端无法过滤频道,只能过滤消息内容
你没法让 Redis 告诉某个客户端“你只能看到 user:123 频道”,因为频道级隔离不存在。唯一可控的是消费后的处理逻辑:
- 收到消息后先校验 JSON 结构,拒绝字段过多、含
eval/system等敏感字符串的消息 - 限制单条 payload 长度(如截断 >1MB 的消息),避免 OOM
- 自动剥离以
_meta_开头的字段,防止元数据注入 - 别指望 Lua 脚本拦截——
EVAL在SUBSCRIBE上下文中被禁止执行
最常被忽略的一点:频道命名本身就会泄露业务语义。用 ch1、ch2 这类无意义名称,再靠外部映射表关联真实含义,比暴露 payment:refund:fail 安全得多。










