Redis PUB/SUB防护需从服务端禁用PUBLISH等高危命令、强制密码认证与绑定内网地址,消费者须截断长度、校验JSON、剥离非业务字段,Lua脚本禁止拼接命令名且用户输入须严格校验。

Redis 的 PUB/SUB 本身不校验消息内容,PUBLISH 命令一旦放行,任意字符串都能发到任意频道——包括含 eval、system(、JSON 注入字段或超长二进制载荷的消息。防护必须落在“谁发”和“怎么收”两个环节,不能依赖中间层过滤。
如何禁止未授权客户端执行 PUBLISH
应用层鉴权拦不住直连 Redis 的攻击者,必须从服务端掐断入口:
- 在
redis.conf中彻底禁用:rename-command PUBLISH "";若业务确实需要,改用白名单别名:rename-command PUBLISH "safe_publish" - 强制启用密码认证:
requirepass your_strong_password,且密码绝不可硬编码在前端或公开配置中 - 用
bind严格限定监听地址,例如只绑127.0.0.1或内网 IP 段,严禁bind 0.0.0.0 - 生产环境禁用
CONFIG、DEBUG、FLUSHALL等高危命令:rename-command CONFIG ""等
为什么不能只靠应用层过滤 message payload
攻击者绕过业务代码直连 Redis 执行 PUBLISH 后,恶意消息会直接抵达消费者。此时再做校验已晚,常见后果包括:
-
JSON.parse()遇到畸形结构或超深嵌套直接栈溢出 - 正则表达式处理含递归模式的 payload 触发 ReDoS
- 消息体 >1MB 但消费者未设长度限制,导致内存暴涨甚至 OOM
- 携带 Lua 脚本片段(如
return os.execute)被下游误解析执行
所有 SUBSCRIBE 客户端必须在接收后立即做三件事:截断长度(如 >1MB 丢弃)、校验 JSON 结构有效性、剥离非业务字段(如 __debug、cmd)。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
如何安全使用 Lua 脚本处理订阅消息
如果消费者用 EVAL 处理收到的消息,脚本本身就成了注入入口。关键约束如下:
- 禁止在脚本里拼接命令名:
redis.call(cmd_name .. "_ex")是高危写法 - 禁止调用
loadstring、load或任何动态加载逻辑 - 所有用户输入仅作为
ARGV传入,且在脚本中先用tonumber()或正则校验格式,失败即return error("invalid arg") - 避免用
pcall包裹敏感调用做条件分支——错误响应差异可能被用于时序探测 - 权限判断、数据边界检查等强逻辑不要下沉到 Lua,留在客户端做
频道名本身也是攻击面,不能忽略
Redis 不校验频道名合法性,攻击者可批量创建 tmp_*、log_20260408* 等规律性频道刷屏。防御要点:
- 定期用
PUBSUB CHANNELS "tmp_*"扫描异常频道名 - 对匹配到的频道,再用
SCAN 0 MATCH "tmp_*" COUNT 1000确认是否有实际 key 存在(空频道不会出现在PUBSUB CHANNELS结果中) - 确认为垃圾频道后,向其发送一条带终止标识的消息(如
{"type":"cleanup"}),由消费者主动退订并清理本地状态 - 注意:
UNSUBSCRIBE只影响当前连接,Redis 无删除频道命令;频道最终消失依赖无人PUBLISH维持其活跃
真正难防的是“合法身份+非法内容”的组合:一个通过了 ACL 和密码认证的客户端,仍可能因参数校验松懈而成为注入跳板。每个 ARGV、每条 message.payload、每个频道名,都得当成潜在攻击载荷来对待。

















