Redis 默认配置下,一旦暴露在公网或内网被未授权访问,攻击者能直接通过 CONFIG SET 指令将数据持久化路径改写到系统计划任务目录,或者通过 FLUSHALL 清空全部缓存数据。这不是漏洞扫描器上的理论风险,而是每天都在发生的真实入侵。处理这类风险,最直接有效的操作不是加防火墙,而是从 Redis 内部把危险命令禁用或改名。

很多人以为设置一个复杂密码就够了。实际上,如果攻击者已经进入内网,或者通过 SSRF 打到了 Redis 的 6379 端口,密码验证在暴力破解和字典攻击面前并不保险。更致命的是,Redis 的指令执行速度极快,单条危险命令就可能在毫秒级完成破坏。所以,关闭危险命令和 rename 配置是数据库加固的第一步,也是性价比最高的安全投入。

哪些命令属于高危指令

Redis 的危险命令可以分成几类。第一类是数据清除类,比如 FLUSHALL 和 FLUSHDB,它们会无条件删除所有数据库或当前库的全部键值,没有任何二次确认机制。第二类是配置修改类,CONFIG SET 和 CONFIG REWRITE 能直接修改 Redis 运行参数,包括 dir 和 dbfilename,这是写计划任务、写 SSH 密钥的常用手法。第三类是脚本执行类,EVAL 和 EVALSHA 可以执行 Lua 脚本,攻击者能用它绕过部分安全限制或执行复杂逻辑。第四类是持久化触发类,BGSAVE 和 BGREWRITEAOF 本身不致命,但配合 CONFIG SET 改过的路径,就能把内存数据写入任意文件。第五类是主从复制类,SLAVEOF 和 REPLICAOF 能让当前实例变成攻击者控制节点的从库,从而实现数据窃取或进一步渗透。

还有一些命令在特定场景下同样危险。DEBUG 命令族里的 DEBUG SLEEP 可以造成拒绝服务,DEBUG RELOAD 可能触发意外行为。SHUTDOWN 能直接关闭 Redis 服务。KEYS 命令虽然不是直接破坏性指令,但在数据量大的生产环境执行 KEYS * 会阻塞主线程,造成服务不可用,属于运维层面的高危操作。

关闭命令与 rename 的底层逻辑

Redis 从 2.8 版本开始就在配置文件中提供了 rename-command 指令。它的设计思路不是从代码层面删除命令,而是在命令表注册阶段把原命令名替换成一个空字符串或者一个新名字。当客户端发送被 rename 成空串的命令时,Redis 直接返回 ERR unknown command 错误。这个机制的优势在于,它不修改 Redis 源码,不需要重新编译,只需要改一行配置就能生效。

rename-command 的语法非常直接。在 redis.conf 里写 rename-command FLUSHALL "" 就是把 FLUSHALL 禁用,双引号中间不留任何字符。如果写 rename-command FLUSHALL "abc123def",那么原本的 FLUSHALL 就失效了,只有知道新名字 abc123def 的人才能调用。这种改名策略适合那些偶尔需要在运维脚本里使用但又不想被外部随意调用的命令。

需要特别注意,rename-command 是在服务端解析命令名的阶段生效的,这意味着它会影响所有客户端,包括本地回环地址的连接。如果你把 CONFIG SET 改成了一个复杂名字,那你自己用 redis-cli 执行监控脚本时也必须带上新命令名。这在自动化运维里需要同步更新所有相关脚本和工具链。

生产环境推荐禁用的命令清单

一个经过实战检验的最小化禁用列表如下。FLUSHALL 和 FLUSHDB 直接禁用,除非你的业务逻辑真的需要在运行时清空数据库,绝大多数应用都不应该有这种需求。CONFIG SET 和 CONFIG REWRITE 建议禁用,如果确实需要运行时调整参数,可以改成复杂的新名字并严格限制调用来源。EVAL 和 EVALSHA 如果业务不使用 Lua 脚本,直接禁用;如果使用,建议改成新名字。SLAVEOF 和 REPLICAOF 在主节点上必须禁用,从节点按需保留。SHUTDOWN 直接禁用,重启操作应该由系统级服务管理工具完成。DEBUG 整个命令族建议禁用,线上环境不需要调试指令。BGSAVE 和 BGREWRITEAOF 如果不需要手动触发持久化,也可以禁用或改名。

对于 KEYS 命令,虽然不能直接 rename 成空串(部分监控和运维工具依赖它),但可以改成一个只有内部运维人员知道的名字,同时配合 SCAN 命令逐步替换业务代码中的 KEYS 调用。SCAN 是渐进式迭代,不会阻塞主线程,更适合生产环境。

配置文件的详细操作步骤

编辑 redis.conf 文件,找到 SECURITY 区域或者直接在文件末尾添加以下配置。每一行对应一个命令的处理策略。

# 直接禁用高危命令
rename-command FLUSHALL ""
rename-command FLUSHDB ""
rename-command CONFIG ""
rename-command SHUTDOWN ""
rename-command DEBUG ""

# 改名为复杂字符串,仅内部使用
rename-command EVAL "e71a2b9c4d0f5e8a1b3c6d9f0e2a4b7c"
rename-command EVALSHA "f82b3c0d1e4a5f6b7c8d9e0f1a2b3c4d"
rename-command BGSAVE "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"
rename-command BGREWRITEAOF "b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7"
rename-command SLAVEOF "c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8"
rename-command REPLICAOF "d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9"

保存配置文件后,重启 Redis 服务使配置生效。可以用 redis-cli 连接后直接输入被禁用的命令名来验证,应该返回 -ERR unknown command。如果返回了其他错误或者命令执行成功,说明配置没有生效,需要检查配置文件路径是否正确、Redis 是否确实加载了该配置文件。

如果不想重启 Redis,可以通过 CONFIG SET 动态修改 rename-command 参数,但前提是 CONFIG SET 还没被禁用。执行 redis-cli CONFIG SET rename-command FLUSHALL "" 可以立即禁用 FLUSHALL。不过动态修改的配置在重启后会丢失,必须同步写入 redis.conf 才能持久化。

rename 配置的进阶策略与注意事项

改名不是随便加几个随机字符就完事。新命令名需要满足几个条件:足够长,至少 32 位以上,防止被暴力猜解;包含大小写字母和数字混合,避免使用字典单词;每个命令的新名字应该独立且不相关,防止攻击者通过规律推导。可以把新名字存储在内部密码管理工具里,运维团队通过加密共享访问。

还有一个容易被忽略的点:Redis 的 MONITOR 命令会实时输出所有执行过的命令。如果你在 MONITOR 开启的情况下执行了被改名的命令,新命令名会以明文形式出现在监控流中。攻击者如果已经拿到 MONITOR 权限,就能看到你输入的那个复杂字符串。因此,MONITOR 命令本身也应该被禁用或改名。

在哨兵模式和集群模式下,rename-command 的配置需要更加谨慎。哨兵节点会向 Redis 实例发送 INFO、PING 等命令,这些命令不能禁用。集群模式下的节点间通信依赖 CLUSTER 命令族,也不能随意改名。对于主从复制相关的命令,如果禁用了 SLAVEOF,那从库无法通过正常方式挂载到主库,需要提前规划好复制链路的建立方式。

多层防御:rename 不是终点

把危险命令禁用或改名之后,安全水位已经大幅提升,但这只是第一层防线。接下来需要配合网络层访问控制,比如通过 iptables 或云安全组限制 6379 端口的来源 IP,只允许应用服务器和运维跳板机连接。同时,开启 Redis 的 protected-mode 参数,这个选项在 3.2 版本之后默认开启,当 Redis 绑定到所有网卡且没有设置密码时会拒绝外部连接。

密码策略上,requirepass 设置的密码长度至少 32 位,包含大小写字母、数字和特殊符号。如果 Redis 版本在 6.0 以上,强烈建议启用 ACL 功能。ACL 可以创建多个用户,每个用户拥有独立的密码和命令权限集合。相比单一的 requirepass,ACL 能做到更细粒度的控制。你可以创建一个只读用户给监控系统,创建一个拥有全部权限但只能从特定网段登录的管理员用户,再创建一个仅能执行特定命令的应用用户。

一个典型的 ACL 配置示例如下:

# 先禁用默认用户
ACL SETUSER default off

# 创建管理员用户,仅限内网访问
ACL SETUSER admin on >复杂密码 ~* &* +@all -@dangerous

# 创建应用用户,只能操作特定键前缀
ACL SETUSER app on >应用密码 ~app:* +get +set +del +expire -@dangerous

# 创建只读监控用户
ACL SETUSER monitor on >监控密码 +info +ping +slowlog +memory -@dangerous

ACL 中的 -@dangerous 会禁用 Redis 预定义的危险命令类别,包括 FLUSHALL、FLUSHDB、CONFIG、SHUTDOWN、DEBUG 等。这和 rename-command 形成双重保护,即使 rename 配置被意外覆盖,ACL 层面仍然会拦截危险指令。

日志审计同样不可忽视。把 loglevel 设置为 notice 或 warning,确保所有异常命令尝试都会被记录。定期分析 Redis 日志中是否出现 -ERR unknown command 错误,大量此类错误可能意味着有人在尝试探测被改名的命令。结合 slowlog 功能,把慢查询阈值调低到 10 毫秒左右,记录所有执行时间异常的操作,这能帮助发现暴力破解或异常数据扫描行为。

最后,定期更新 Redis 小版本。很多安全机制是在小版本迭代中逐步完善的,比如 protected-mode 的默认行为调整、ACL 功能的持续增强。保持版本在官方支持的最新稳定版,能避免已知漏洞被利用。升级前在测试环境验证 rename-command 和 ACL 配置的兼容性,确保新版本没有改变这些安全参数的解析逻辑。

把这些措施组合起来,Redis 实例的安全防护就不再是单点依赖,而是从命令层、用户层、网络层、审计层构成的纵深防御体系。攻击者即便绕过了某一层,也会在下一层被拦截。这套方案不需要额外采购安全设备,完全基于 Redis 内置功能实现,对性能的影响几乎为零,是所有 Redis 生产环境都应该执行的基础加固动作。