Redis 的安全问题,本质上不是它不够强,而是大多数部署在“裸奔”。很多人认为 Redis 运行在内网就高枕无忧,但横向移动攻击一旦突破边界,未设防的 Redis 就是一台完美的“提权跳板机”。解决这个问题的核心路径有两条:一条是启用“保护模式”构建基础防线,另一条是启用 ACL(访问控制列表)实现用户权限的精细控制。下面直接拆解这两大机制的具体配置、验证方法和生产落地策略。
安全模式:被误解的“新手保护”
很多人把 Redis 的“保护模式”(Protected Mode)当成一个简单的开关,甚至觉得它碍事,直接关掉了事。实际上,保护模式是 Redis 在没有设置密码且未绑定特定接口时,强制拒绝外部连接的一种安全兜底机制。它的逻辑很直接:如果你没有通过 requirepass 设置密码,也没有用 bind 指令限制监听网卡,那么任何非本地回环地址(127.0.0.1)的连接请求都会被直接拒绝。
你可以通过以下命令检查当前状态:
127.0.0.1:6379> CONFIG GET protected-mode 1) "protected-mode" 2) "yes"
如果返回“yes”,说明保护模式是开启的。但要注意,保护模式并不是万能的。一旦你设置了密码,或者将 bind 绑定到了 0.0.0.0,保护模式就会自动让位,不再拦截外部连接。这就意味着,如果你的密码是“123456”这种弱口令,保护模式也救不了你。所以,保护模式只是第一道门槛,真正的精细化控制必须靠 ACL。
ACL 核心机制:从“一码通”到“最小权限”
在 Redis 6.0 之前,所有客户端共享同一个密码,一旦登录就拥有了全部命令的执行权限。这种“一码通”模式是灾难性的,任何一个客户端被劫持,攻击者就能执行 FLUSHALL 清空数据,或者通过 CONFIG SET 修改配置。ACL 的出现彻底改变了这个局面,它允许你创建多个用户,为每个用户定义不同的密码、可执行命令和可访问的键空间。
ACL 的权限控制粒度细到什么程度?你可以精确到“只允许用户 A 对以 user: 开头的键执行 GET 和 SET 命令,且每秒最多请求 10 次”。这种精细度在微服务架构中至关重要,比如订单服务只需要读写订单缓存,完全没有必要让它接触到用户会话数据。
实战:创建和管理 ACL 用户
我们先从最基础的用户创建开始。Redis 的 ACL 用户管理通过 ACL SETUSER 命令完成,语法非常直观:
ACL SETUSER <username> <rule> [rule ...]
创建一个只能执行 GET 和 SET 命令的用户:
ACL SETUSER app_user on >strong_password ~* +@read +@write -@dangerous
这条命令拆解开来看:on 表示启用用户;>strong_password 设置密码;~* 允许访问所有键;+@read 和 +@write 允许读写命令组;-@dangerous 则显式禁用了危险命令组(包含 FLUSHALL、CONFIG、SHUTDOWN 等)。这种“先加后减”的策略比逐个添加命令更安全,因为 Redis 的 ACL 默认是“全部拒绝”,你必须显式授权。
如果你需要更严格的键空间隔离,可以这样配置:
ACL SETUSER order_service on >order_pass ~order:* +@all -@dangerous
这个用户只能操作以 order: 为前缀的键,即使它拥有 @all 的权限组,也无法越界访问 user: 或 session: 的数据。验证权限非常方便,使用 AUTH 切换用户后,尝试执行越权命令:
127.0.0.1:6379> AUTH order_service order_pass OK 127.0.0.1:6379> GET user:1001 (error) NOPERM this user has no permissions to access one of the keys used as argument
错误信息明确指出了问题所在,这在调试微服务权限时非常有用。
持久化 ACL 配置:避免重启丢失
通过命令行设置的 ACL 规则在 Redis 重启后会丢失,必须写入配置文件或使用 ACL SAVE 命令。推荐的做法是直接在 redis.conf 中维护 ACL 规则,格式如下:
user default off user admin on >admin_password ~* +@all user readonly on >readonly_pass ~* +@read
注意第一行:user default off。这是关键一步,默认用户必须禁用或设置强密码。如果保留 default 用户的空密码状态,整个 ACL 体系就形同虚设。如果你不想修改主配置文件,也可以使用外部 ACL 文件,通过 aclfile 指令加载:
aclfile /etc/redis/users.acl
在运行时,修改完 ACL 规则后执行 ACL SAVE 即可将当前规则持久化到该文件。ACL LOAD 则可以从文件重新加载规则,这在批量更新用户权限时非常高效。
生产环境的 ACL 最佳实践
在实际生产环境中,ACL 的配置不是一劳永逸的,需要遵循几个硬性原则。第一,永远为每个微服务或应用实例创建独立的用户,不要共享账号。第二,严格限制键空间,即使同一个服务内部,如果模块之间没有数据共享需求,也应该通过键前缀隔离。第三,启用命令重命名机制,将危险命令映射为空字符串,这是比 ACL 更底层的防护:
rename-command FLUSHALL "" rename-command CONFIG ""
第四,利用 ACL LOG 监控权限拒绝事件。当应用因为权限问题报错时,你可以通过以下命令查看最近的拒绝记录:
ACL LOG 10
这会列出最近 10 条被拒绝的命令,包含时间戳、用户、客户端 IP 和具体命令。这个日志是排查微服务权限配置错误的第一手资料,也是发现潜在攻击行为的重要线索。
第五,定期审计 ACL 规则。Redis 提供了 ACL LIST 命令,可以列出所有用户的规则摘要:
127.0.0.1:6379> ACL LIST 1) "user admin on #hash... ~* +@all" 2) "user order_service on #hash... ~order:* +@all -@dangerous"
你可以将这个输出保存下来,定期与预期规则比对,防止配置漂移。
安全模式与 ACL 的协同防御
保护模式和 ACL 不是二选一的关系,而是纵深防御的两个层面。保护模式确保了“无密码不暴露”的底线,ACL 则解决了“有密码也分权”的问题。一个典型的加固流程是这样的:先确认保护模式开启,然后设置 default 用户为 off 或强密码,接着为每个业务创建最小权限的 ACL 用户,最后通过 rename-command 彻底禁用危险命令。完成这些步骤后,即使 Redis 暴露在公网,攻击者也无法通过弱口令或未授权访问造成实质性破坏。
还有一个容易被忽视的细节:Redis 的日志输出。当 ACL 拒绝一个命令时,日志中会记录类似这样的信息:
-NOAUTH Authentication required. -NOPERM this user has no permissions to run the 'flushall' command
将这些日志接入集中式日志分析平台,设置告警规则,一旦出现大量权限拒绝,立即触发安全响应。这种主动监控比被动防御更有价值。
Redis 的安全加固从来不是技术难题,而是意识问题。保护模式提供了基础保障,ACL 实现了权限的最小化,两者结合就能将 Redis 从攻击者的“软柿子”变成“硬骨头”。在当下的网络环境中,任何没有启用 ACL 的 Redis 实例,本质上都是在裸奔,只是攻击者还没找上门而已。
