你在生产环境里见过不设置密码的Redis吗?我见过,而且是在一场惨烈的故障里。当时一台低配服务器上跑着一个业务量不大的Redis实例,开发图省事没配密码,只做了内网IP绑定。结果某天下午这台服务器CPU飙到100%,上去一看,Redis里多了个可疑的key,里面塞着一段下载脚本——公网扫描器正通过主从复制往机器里塞挖矿程序。最后只能杀进程、清数据、改配置、换IP,折腾了一整晚。
这件事给我的教训很直接:Redis的默认安全模型假定“网络是可信的”,一旦这个假定被打破,密码就是最低限度的防线。不管你是单机、主从、哨兵还是集群,把密码配好,是所有Redis上生产的第一步。接下来我就围绕“Redis设置密码”这件事,从最基本的requirepass讲到Redis 6+的ACL用户体系,再到客户端连接、密码轮换和主从/集群场景下的配合方式。无论你是刚装好Redis的入门用户,还是正在维护一套集群的运维,都能在这里找到可以直接照做的方案。
下面先说清楚:为什么Redis的密码不是可选项。
1. Redis默认配置下的安全风险:不设密码到底意味着什么
1.1 默认状态下Redis的门是半掩着的
先从结论说起。Redis 3.2之后的默认配置会开启protected-mode,同时监听地址是127.0.0.1,所以装完Redis不碰配置直接启动,外部机器连不上,表面上很安全。但protected-mode的机制比很多人以为的更细:当它开启、实例没有配置密码、并且监听地址包含非回环地址时,Redis会拒绝来自外部网络的连接并返回错误提示。这就像一个“默认拒绝外部”的开关。
问题在于,这个开关的优先级低于认证。一旦你在配置里加了requirepass,相当于明确声明“本实例允许外部通过认证访问”,protected-mode对外部连接的拦截就会让位给认证机制。很多团队是这么出事的:装好Redis后随手bind 0.0.0.0,没设密码,发现外网连不上,就以为很安全;后来有人为了远程访问加了密码,结果密码设置得太简单,或者密码本身又被扫到了,于是实例就暴露了。说白了,protected-mode只是默认保护,设置密码才是主动的安全声明。
更麻烦的是扫描器。公网上有大量自动化脚本,每时每刻都在扫描6379、6380这类默认端口。它们拿到开放端口后,第一件事就是执行redis-cli -h <ip> ping这类无害命令,看有没有返回PONG。一旦发现一个不需要密码的实例,后续攻击链马上跟进:写入crontab、通过主从复制写文件、用Lua脚本枚举数据、把库里的数据搬走再塞入勒索信息。
如果Redis里有业务缓存,最直接的损失是数据泄密;如果Redis开启了持久化且能被写入,攻击者还可能利用主从复制或其他特性在磁盘上写出恶意文件,把数据服务器变成矿机,甚至在部分场景下拿到执行权限。这些不是危言耸听,安全公告里都能看到真实案例。
1.2 哪些场景最容易出问题
根据我这几年的运维经验,下面这几类场景最常见:
- 开发/测试环境直接绑定0.0.0.0,图省事不设密码,内网另一台机器被攻破后横向移动,Redis跟着遭殃。
- 把Redis部署在云服务器上,安全组规则写了0.0.0.0/0(所有IP),等于把端口全开给公网。
- 用Docker启动Redis时没有做任何认证配置,端口又映射到宿主机。
- 公司内部公共Redis,多个团队共用,有人误执行FLUSHALL导致缓存全清。
- 为了临时联调,把Redis端口用frp或Nginx反代暴露到外网,忘了加密码。
这些场景只要碰到一个,就有必要设置密码。可能有人会说“我们的Redis只在内网,没啥风险”,但内网横向渗透在真实攻击中非常常见,尤其是跳板机失守的情况下,内网每个开放端口都可能成为下一跳。密码虽然不能替代网络隔离,但它能把“意外连接”变成“必须通过认证才能连接”,这个门槛就是一层非常实用的兜底。
1.3 设置密码能挡住什么、挡不住什么
给Redis设置密码后,能挡住以下几类问题:
- 公网扫描器和未授权访问脚本:它们不会花时间猜一个强随机密码。
- 内网误连:有人开错端口、指错IP,会被认证报错拦住,而不是直接拿到数据或执行危险操作。
- 误操作:没有认证权限的普通人员无法直接执行FLUSHALL、CONFIG等危险命令。
但密码挡不住的是:合法用户误操作、应用代码里的弱密码被泄露、以及TLS缺失状态下流量被窃听导致密码泄露。所以密码是必要不充分条件,后面我还会讲怎么配合ACL和网络策略一起用。
2. requirepass配置方式:配置文件、命令行与动态切换全走一遍
2.1 最基础的做法:在redis.conf里设置requirepass
如果只用一句话回答“Redis怎么设置密码”,那就是:在redis.conf里加上一行
requirepass YourStrongPassword2024然后启动时指定配置文件。如果是系统自带的Redis,conf文件通常在/etc/redis/redis.conf或者安装目录下;如果是源码编译,一般是redis.conf。启动命令:
redis-server /etc/redis/redis.conf设置完成后,用redis-cli连上去执行命令就会出现:
127.0.0.1:6379> keys * (error) NOAUTH Authentication required.这时候必须先认证:
redis-cli -p 6379 127.0.0.1:6379> auth YourStrongPassword2024 OK 127.0.0.1:6379> keys * (empty array)需要注意的坑:requirepass在redis.conf里的顺序无所谓,但要注意不要把好几份conf文件搞混。尤其用Docker部署时,宿主机和容器里的conf文件路径经常不一样,改错了配置等于白改。我自己就犯过一次:在宿主机上改了redis.conf,容器内启动时挂载的是另一个目录的conf,结果改了半天还是连不上。
2.2 命令行启动:不写配置文件也能设置密码
临时启动一个测试实例时,可以不带配置文件,直接通过参数传:
redis-server --requirepass mypass --port 6379这种方式适合临时验证排查,但我不建议在生产环境用。原因很简单,命令行参数会被进程列表看到(ps aux会显示进程启动命令),如果密码写在里面,等于是把密码暴露给了所有能登录这台机器的用户。
如果你只是临时测试,又不想留痕,可以用一个更稳妥的方法:先启动不带密码的Redis实例,然后通过redis-cli连进去执行CONFIG SET。这样密码只会出现在配置文件和Redis运行时内存里,不会出现在进程参数里。
2.3 动态修改:不改配置文件的情况下重置密码
Redis允许在运行时动态修改requirepass,这在密码轮换场景下非常关键,流程是这样:
# 先连接上实例 redis-cli -p 6379 # 执行过auth认证 auth oldpass # 修改密码 config set requirepass newpass # 让配置持久化到磁盘 config rewrite执行完config set requirepass newpass之后,当前已认证的连接不会被踢掉,但新连接的客户端必须使用newpass。这是Redis的一个独特行为,很多第一次操作的人会愣一下:为什么我改了密码自己还没断?原因就是Redis对已认证连接保持信任,不主动断开,只有新连接才需要走新的认证流程。
关于config rewrite需要多说一句:它会把当前生效的配置写回redis.conf。如果你用config set临时改了密码却忘了config rewrite,重启后Redis会回到旧密码,这个问题我后面专门讲。
还有一点很容易忽略:config set requirepass本身是一条CONFIG命令,在设置了requirepass之后,未认证连接无法执行CONFIG命令,会直接报NOAUTH。所以“用config set设密码”这个动作,必须由一个已经知道当前密码的连接来完成。通俗地说:你不能给一台完全未知密码的Redis设置新密码,必须先用旧密码登录进去。