年前帮一位朋友排查Redis实例被清库的事故,翻完日志才发现,问题根本不在什么高深的漏洞利用上——那台Redis部署在公网服务器上,bind是默认配置,protected-mode虽然开着,但requirepass没设,等于把家门的钥匙挂在了门框上。攻击者一条 FLUSHALL 命令下去,缓存数据全没了,还被人塞了一个定时任务。这个教训让我一直想写一篇把“设置Redis访问密码”这件事彻底讲清楚的文章:从为什么必须设,到原理是什么,再到Windows、macOS、Linux、Docker下怎么配置,最后是客户端和可视化工具怎么连、线上踩过的坑怎么排。这篇文章适合刚接触Redis的新手,也适合部署过Redis但没认真管过认证环节的运维和开发,照着做一遍,能省掉很多半夜被叫起来看事故的尴尬。
1. 裸奔的Redis到底有多危险
1.1 未设密码的真实事故
Redis默认是不带认证的,也就是说,只要端口能连通,任何人都可以不输入账号密码直接执行命令。这个特性在本地开发环境很舒服,redis-cli一敲就进去了,但拿到服务器上就成了大问题。前几年大量针对Redis的入侵事件,用的就是这种未授权访问漏洞:攻击者扫描公网上的6379端口,连上后写 CONFIG SET dir /var/spool/cron/,再写 CONFIG SET dbfilename root,把恶意任务写到cron目录里,随后触发Redis持久化,就在服务器上拿到了定时执行命令的能力。整个过程不需要任何密码,也不需要什么高深技巧,扫描工具全网一跑就能批量捞到肉鸡。
这类事故的影响面不止数据泄露。Redis里存着登录态、业务缓存、接口限流计数器,数据被清空可能导致业务瞬间过载甚至雪崩。更麻烦的是,攻击者一旦能执行 CONFIG 命令,就能改写Redis运行参数,甚至结合系统漏洞实现远程命令执行。我见过不少团队把Redis当“内网服务”所以不设密码,结果内网又有人中了钓鱼邮件被横向渗透,Redis直接就变成了跳板。
1.2 Redis默认配置到底管住了什么
安装好Redis后,默认的redis.conf里有关安全的部分大概是这样:bind 127.0.0.1 -::1 默认只监听本机回环地址;protected-mode yes 开启保护模式;requirepass 这项默认是被注释掉的,也就是没有密码。这三个配置组合起来,在“本机只有你一个人用”的前提下是安全的,因为服务不对外监听,外部根本连不上。但一旦你把 bind 改成 0.0.0.0,或者部署在云服务器上为了其他机器能访问而放开了监听地址,那 protected-mode 就未必能挡住所有人了。
protected-mode 的机制是:当服务没有设置密码,又监听了非本机地址时,Redis会拒绝来自非本机的连接请求。听起来挺安全对吧?但实际场景里,很多同学改了bind后又把 protected-mode 顺手设成 no,原因是要配合某些客户端或主从复制的网络连通性,结果密码又没设,等于把最后一道门也拆了。正确做法是:只要Redis需要被其他机器访问,就必须设置 requirepass,让认证成为服务接受的硬性前提。
1.3 哪些部署场景必须设置访问密码
简单说,只要Redis的端口不是只对本机开发环境开放,就必须设置密码。三类场景最常见:
第一类是云服务器上部署Redis,不管你是买了轻量应用服务器还是云主机,只要6379端口暴露在公网,或者同一账号下的多台机器通过内网IP互相访问,都算在内。第二类是容器环境,Docker启动Redis时如果做了端口映射,宿主机网卡上的6379端口默认就通了,别人扫到就能连。第三类是公司内网,别以为内网就干净,办公网里各种扫描器、测试脚本、离职员工的跳板机,都可能拿到Redis端口。
有同学会问:“那我用防火墙只允许特定IP访问Redis,不设密码行不行?”我的回答是:防火墙是网络层控制,密码是应用层认证,两者是互补关系而不是替代关系。防火墙规则可能配错、服务器可能被入侵后成为内网跳板、云安全组可能在重装或迁移时被重置成默认放行,这些情况一走错,密码就是最后一道防线。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心原理:requirepass与AUTH认证机制
2.1 requirepass:服务端的一把锁
Redis的访问密码机制核心就是一个配置项:requirepass。它的工作方式特别简单直接——在客户端发送任何命令之前,必须先通过认证;服务端在收到一条命令后,会先检查当前连接是否处于已认证状态。如果没认证,直接返回 NOAUTH Authentication required 的错误;如果已认证,就正常执行命令。
设置密码的行为就像是给Redis实例本身上了一把只能由管理员打开的锁。这把锁的验证方式是常数时间的字符串比较,不会因为密码很长就拖慢性能。实际压测下来,AUTH命令本身的开销在微秒级别,比起业务命令和网络传输,完全可忽略。这也是为什么我一直建议密码要设得足够长足够复杂——既然性能上没有负担,就没有任何理由用一个弱密码把自己的数据交出去。
需要注意一个细节:requirepass 设置的是Redis默认用户(default user)的密码。在Redis 6.0以前,认证只有这一种维度;Redis 6.0引入了ACL后,你可以为不同用户设置不同密码和权限范围,但 requirepass 仍然是最基础、最通用的入口。
2.2 客户端认证的完整交互过程
当Redis启用了 requirepass,客户端要正常使用服务,需要经历一次认证握手。用 redis-cli 演示最直观:
bash复制# 未认证时执行命令,直接报错
127.0.0.1:6379> GET user:name
(error) NOAUTH Authentication required.
# 执行AUTH命令认证,密码正确返回OK
127.0.0.1:6379> AUTH MyStrongPass@2024
OK
# 认证后命令正常执行
127.0.0.1:6379> GET user:name
"redis"
这个过程其实可以类比成进入小区门禁:进门闸机先验证你的门禁卡,验证通过后,之后每走一步都不会再查(因为TCP连接是长连接,认证状态在连接生命周期内持续有效);如果你连接上了却没认证,服务端就会在每次命令前拦你一下。在Redis 6.0及以上版本,AUTH命令支持用户名加密码的形式:AUTH username password。如果服务端只配置了 requirepass,那默认用户名就是 default,可以省略。
2.3 密码明文存储的现实与缓解措施
不少人在配置文件中第一次看到 requirepass 时都会犯嘀咕:这密码明晃晃写在redis.conf里,被人看到配置文件不就等于密码泄露了吗?确实是这样。Redis的配置文件对密码没有做加密存储,这是设计上“重实用、轻加密”的结果。所以你能做的事情有三件:
第一是严格控制配置文件的读取权限。配置文件建议设置成 600 或 640,只有Redis运行用户和管理员用户能读。第二是不要在同一份配置里写生产密码和随意分享的开发配置,尤其是当团队使用公共服务器、代码仓库、配置中心时,尽量避免把生产Redis的密码塞进通用的模板配置里。第三是配合ACL体系做权限分层,比如给开发测试环境单独建用户,把写权限收回去,这样即使密码泄露,破坏面也有限。
3. 多平台实操:配置文件、命令行与Docker
3.1 通用配置入口:redis.conf里的requirepass
不管什么平台,设置Redis密码的第一入口都是修改配置文件 redis.conf。打开它,找到下面这一行:
code复制# requirepass foobared
它旁边的英文注释也写得很明白:把这一行取消注释,并把 foobared 替换成你自己设定的密码即可。修改后的效果:
code复制requirepass MyStrongPass@2024
这里有几个细节要特别留意。第一,密码最好不要包含单引号、双引号、$、空格这些会被命令行或配置文件解析器特殊处理的字符,否则后面用 redis-cli -a 或者拼连接串时会遇到各种转义问题。第二,requirepass 指令在配置文件里是全局唯一的,如果你写了两行,Redis启动时会以最后一行生效,容易造成“我明明改了密码怎么还是旧密码”的困惑。第三,密码长度建议至少16位,混合大小写字母、数字和符号,不要用 123456、admin、redis 这种字典词,别以为内网没人看,公网扫描器分分钟爆破。
3.2 Linux服务器配置与验证全流程
Linux下最常见的Redis安装方式有两种:系统包管理工具安装和源码编译安装。但无论哪种,流程都差不多。
先用包管理器找到配置文件位置。apt 安装的Redis(如Ubuntu、Debian),配置文件一般在 /etc/redis/redis.conf,服务名为 redis-server。yum 安装的(如CentOS、Rocky Linux),配置文件在 /etc/redis.conf 或 /etc/redis/redis.conf,服务名一般是 redis 或 redis-server。源码编译安装的,配置文件就在你解压并编译的目录下,比如 /opt/redis-7.0.15/redis.conf。
修改配置文件:
bash复制sudo vim /etc/redis/redis.conf
找到 # requirepass foobared,取消注释并修改为:
code复制requirepass MyStrongPass@2024
保存退出后重启服务:
bash复制# 使用systemd的现代发行版
sudo systemctl restart redis-server
# 旧版本
sudo service redis-server restart
这一步很多人踩过坑:改了配置文件但不重启,Redis不会自动加载新密码。因为 requirepass 属于运行时配置项,它是可以热更新的,但热更新走的是 CONFIG SET 命令而不是改文件。所以改完文件想让它生效,必须重启或者用 CONFIG SET 手动加载。
验证是否生效:
bash复制# 不带密码连接,执行命令应该报NOAUTH
redis-cli -h 127.0.0.1 -p 6379 PING
(error) NOAUTH Authentication required.
# 带密码连接
redis-cli -h 127.0.0.1 -p 6379 -a 'MyStrongPass@2024' PING
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
PONG
3.3 Windows环境:最容易踩的配置文件加载坑
Windows下使用Redis一般是下载免安装的压缩包,比如社区维护的 redis-for-windows 版本(常见的有5.0.14.1等基于Redis 5.x的分支)。解压后的目录里通常有两个配置文件:redis.windows.conf 和 redis.windows-service.conf。前者是手动启动 redis-server.exe 时用的,后者是注册为Windows服务启动时用的。
改配置的步骤和Linux一致,打开 redis.windows.conf,把 # requirepass foobared 改成 requirepass MyStrongPass@2024。真正的坑在启动方式:很多人直接双击 redis-server.exe,这样启动时不会加载任何配置文件,Redis会以默认无密码状态运行,你改的密码根本不会生效。正确手动启动方式是:
bash复制redis-server.exe redis.windows.conf
这样才能加载你设置在 redis.windows.conf 里的密码。如果你用的是Windows服务方式:
bash复制redis-server.exe --service-install redis.windows-service.conf
redis-server.exe --service-start
那就必须修改 redis.windows-service.conf,并且改完后重启服务。我见过好几次这样的情况:同事改了 redis.windows.conf,但服务启动的是另一个配置文件,抓了半天脑袋才找到原因。
还有一个Windows特有的问题:Redis的Windows版本普遍落后于Linux版本,很多特性比如ACL、TLS在Windows版上不完整。如果业务强依赖Redis新特性,建议用Docker Desktop起Linux容器跑Redis,配置方式见3.5节。
3.4 macOS开发机:brew安装后的快速配置
macOS上用Homebrew安装Redis是非常普遍的做法,安装命令是:
bash复制brew install redis
安装完成后,配置文件的位置根据芯片架构有区别:Apple Silicon(M系列)默认在 /opt/homebrew/etc/redis.conf,Intel芯片在 /usr/local/etc/redis.conf。建议用下面的命令直接打开:
bash复制open -e $(brew --prefix)/etc/redis.conf
同样把 requirepass 那一行取消注释并改成自己的密码。重启Redis服务:
bash复制brew services restart redis
如果当初是用 redis-server 手动前台启动的,那就需要先关掉旧进程再重新启动。用brew services方式管理的好处是:开机自启、日志统一、配置文件路径不会自己变。改完文件后用 brew services list 确认redis状态为 started 即可。
3.5 Docker部署:启动参数与挂载配置写法
Docker跑Redis的人越来越多,设置密码有两种方式。第一种最简单,直接通过启动命令参数传:
bash复制docker run -d \
--name redis \
-p 6379:6379 \
redis:7 \
redis-server --requirepass MyStrongPass@2024
注意,--requirepass 的位置在镜像名之后,不是 docker run 的选项,而是传给容器内 redis-server 进程的命令行参数。第二种方式是挂载自定义配置文件:
bash复制docker run -d \
--name redis \
-p 6379:6379 \
-v /path/to/redis.conf:/usr/local/etc/redis/redis.conf \
redis:7 \
redis-server /usr/local/etc/redis/redis.conf
用docker-compose的话:
yaml复制services:
redis:
image: redis:7
container_name: redis
ports:
- "6379:6379"
command: ["redis-server", "--requirepass", "MyStrongPass@2024"]
无论哪种方式,都要记住:容器重启后密码会按照启动命令或挂载的配置文件重新加载,不要在跑着的容器里用 CONFIG SET 改了密码就不更新启动参数,否则下次重启密码就“变回去”了。这也是线上经常出现的“密码莫名重置”问题的根源之一。
4. 密码设好之后:客户端与工具怎么连
4.1 redis-cli命令行的三种认证方式
命令行连Redis带密码,至少有三套姿势。第一套是启动时直接指定密码:
bash复制redis-cli -a 'MyStrongPass@2024'
但这种方式有个安全小隐患:密码会出现在进程列表里(ps -ef 能看到完整参数),如果服务器上有其他人看到进程列表,密码就泄露了。所以redis-cli自己都会打一行Warning提示这点。
第二套是进入交互模式后用 AUTH 命令认证,启动时不带密码:
bash复制redis-cli
127.0.0.1:6379> AUTH MyStrongPass@2024
OK
第三套是利用环境变量 REDISCLI_AUTH,这也是我平时最推荐的方式,密码不会出现在进程参数里:
bash复制REDISCLI_AUTH=MyStrongPass@2024 redis-cli
设了环境变量后,每次连接redis-cli都会自动执行AUTH,交互体验和无密码时几乎一样。
4.2 可视化连接工具的参数填写
可视化工具也是连接Redis的高频场景。官方提供的RedisInsight、社区流行的Another Redis Desktop Manager、经典的Redis Desktop Manager,连接配置的核心字段都一样:地址(Host)、端口(Port)、密码(Password)。填写时注意以下几点。
第一,如果Redis是Docker部署并做了端口映射,Host要填宿主机IP或域名,不要填 localhost 之外的容器IP。第二,如果服务端启用了ACL且为当前用户指定了用户名,工具里一般有“Username”字段可填,对应 AUTH username password 模式;如果只设置了 requirepass,用户名留空或填 default。第三,连接超时问题常常和密码无关,先检查网络和安全组,别一报错就怀疑密码设置错了。
大部分工具在连接成功后还会让你选择要展示的库编号(默认0号库),如果连接时没有提示要密码,那多半说明你连到的Redis实例根本没设密码,赶紧回头检查是不是配置文件没生效。
4.3 主流开发语言客户端的密码配置
Java的Spring Boot项目,配置写在 application.yml 里:
yaml复制spring:
redis:
host: 127.0.0.1
port: 6379
password: MyStrongPass@2024
timeout: 3000ms
Python的 redis-py:
python复制import redis
r = redis.Redis(
host='127.0.0.1',
port=6379,
password='MyStrongPass@2024',
decode_responses=True
)
print(r.ping())
Go的 go-redis:
go复制client := redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379",
Password: "MyStrongPass@2024",
DB: 0,
})
err := client.Ping(context.Background()).Err()
Node.js的 ioredis:
javascript复制const Redis = require('ioredis');
const redis = new Redis({
host: '127.0.0.1',
port: 6379,
password: 'MyStrongPass@2024',
});
这类连接串和配置里设置密码,有几个必须注意的点:配置文件不要提交到公共Git仓库,用环境变量或配置中心管理密码;密码含有特殊字符时需要正确转义;修改密码后所有客户端连接都要同步更新并重启生效,否则只能看到一堆 NOAUTH Authentication required 报错。
4.4 主从复制场景:masterauth别漏了
如果你设置了主从复制,那需要特别关注 masterauth。主节点设置了 requirepass 后,从节点向主节点发起同步时也需要认证。这个认证走的是从节点自己的配置项:masterauth。
打开从节点的配置文件,找到:
code复制# masterauth <master-password>
把它设置为主节点的Redis密码,并取消注释:
code复制masterauth MyStrongPass@2024
如果忘记配置 masterauth,从节点日志里会反复出现 MASTER auth failed,主从连接建立后被断开,同步永远起不来。这个坑在搭建集群、主从、哨兵架构时特别容易踩到:大家都会记得给主库设密码,却忘了从库也需要密码才能拉起同步。
5. 常见问题排查与避坑实录
5.1 认证报错速查表
把我在生产环境遇到过的认证相关报错整理成一张表,按错误信息排查基本一把梭:
| 错误信息 | 可能原因 | 解决方法 |
|---|---|---|
NOAUTH Authentication required |
客户端未发送AUTH命令,或连接池未配置密码 | 在客户端连接配置中补上密码,或连接成功后先执行AUTH |
WRONGPASS invalid username-password pair |
密码错误,或ACL用户名与密码不匹配 | 核对密码和用户名,注意大小写与尾部空格 |
ERR Client sent AUTH, but no password is set |
服务端未设置任何密码,但客户端发起了AUTH | 检查服务端是否加载了正确的配置文件,确认requirepass已生效 |
MASTER auth failed |
主从复制时从节点masterauth未配置或密码错误 | 在从节点设置正确的masterauth并重启复制进程 |
CONFIG SET执行后报错 |
当前用户通过ACL没有CONFIG权限 | 检查ACL设置,给该用户授权,或改用配置账户操作 |
Connection refused |
Redis未启动或监听地址不对 | 先确认端口是否监听,再看防火墙与安全组策略 |
NOAUTH 是最常见的。尤其是Java应用连接池里,如果你改完Redis密码而应用还在用旧密码,它不会第一时间报错,而是会在获取连接后第一次执行命令时报 NOAUTH,日志里会堆一堆异常。排查方向就是先确认“应用配置的密码”和“服务端实际密码”是否一致。
5.2 密码“不生效”的四种典型原因
很多人改完密码发现没生效,排查了一圈才发现问题不在密码本身,而在加载链路。四种典型原因列出来供对照。
第一种,配置文件放行但服务没重启。前面反复强调了,文件里改 requirepass 后必须重启服务,或者用 CONFIG SET requirepass 手动热更新。第二种,Windows上启动时没加载配置文件。双击 redis-server.exe 就是没加载,命令行必须把配置文件路径传进去。第三种,Docker启动时没把 --requirepass 参数传给容器内的redis-server,而是挂在 docker run 上了。第四种,多个配置文件共存,改了一个不是被加载的那个。
我自己的排查顺序是:先用 redis-cli -a 密码 PING 直接验证当前实例的实际状态,如果返回 PONG,说明实例密码已经生效,问题一定出在客户端;如果返回 NOAUTH,说明密码没配好,再回头查配置文件和启动方式。
5.3 特殊字符密码的转义与URL编码坑
密码里用了特殊字符,在配置文件里往往没问题,但到了命令行和客户端连接串里就会出各种怪事。最典型的是 redis-cli -a 直接带密码时,如果密码里有 $、!、空格,Shell会做变量替换或分词,导致实际传给Redis的密码被截断。
比如:
bash复制# 密码是 abc$def,Shell会把$def当成变量
redis-cli -a "abc$def" # 结果可能传成了奇怪的字符串
解决方法是单引号包住密码,并避免在密码里使用单引号本身:
bash复制redis-cli -a 'abc$def'
还有一类坑出现在Spring Boot、JDBC连接串之类的URL风格配置里,密码中的 @、:、# 会被解析成URL的分隔符或Fragment标记,需要做URL编码。比如密码 abc@def 在 redis://:password@host:port 连接串里要写成 abc%40def。我的建议很简单粗暴:配置密码时直接用不含Shell和URL特殊字符的组合,比如大小写字母加数字加 - _,省去后面所有转义烦恼。
5.4 线上安全最后一道防线:配置文件权限
密码设好了,还要管好密码文件本身。requirepass 明文写在redis.conf里,如果这个文件权限是 644(所有用户可读),那服务器上任何一个低权限进程都能把密码读走。生产环境建议把配置文件权限收紧:
bash复制sudo chown redis:redis /etc/redis/redis.conf
sudo chmod 640 /etc/redis/redis.conf
如果用的是Docker,挂载配置文件的宿主机路径也要注意权限,别用 777。此外,配置文件不要放进代码仓库,更不要写在博客和文档里四处传阅。密码轮换时同步更新所有引用它的地方,我见过最心酸的情况是密码改完三个月,才发现某台监控脚本还在用旧密码,结果每天夜里定时任务都在刷错误日志。
6. 进阶:从requirepass到ACL用户权限体系
6.1 Redis 6.0+的ACL基础操作
Redis 6.0引入了ACL(Access Control List),把“一个密码管所有”升级成“多用户、多密码、按权限分配”的模型。你可以为每个应用或每个团队单独建一个用户,限制它能访问哪些key、能执行哪些命令。
创建只读用户的命令:
code复制ACL SETUSER app_readonly on >AppReadOnly@2024 ~cache:* +get +mget +exists +ttl
拆解一下这条命令:on 表示启用该用户;>AppReadOnly@2024 设置密码;~cache:* 限制只能访问 cache: 前缀的key;+get +mget +exists +ttl 允许执行这几个只读命令。除了显式授权的命令,其他命令默认禁止。
也可以在配置文件中直接定义用户,重启后依然生效:
code复制user app_readonly on >AppReadOnly@2024 ~cache:* +get +mget +exists +ttl
启用ACL后,客户端连接时使用用户名加密码认证:
bash复制redis-cli --user app_readonly -a 'AppReadOnly@2024'
如果访问了未被授权的key或命令,Redis会返回 NOPERM this user has no permissions to run the 'set' command 之类的错误。这种精细化的权限控制,比单一密码做问题隔离要强太多了。
6.2 requirepass与ACL共存的使用策略
requirepass 和ACL不是互斥的,而是有层级关系的。requirepass 给的是默认用户 default 的密码,而ACL可以创建独立用户。生产上常见的组合是:保留 default 用户的密码用于管理员操作,同时创建若干低权限用户给不同业务使用。
这样设计的好处是:线上业务连接如果一个应用密码泄露,攻击者拿到的只是一个受限用户,清空数据、改配置这类高危操作依然做不了。管理员密码泄露虽然严重,但可以用ACL的 +config、+shutdown 等权限进一步细分,甚至给管理员账号也设置只能操作某些前缀key。
配置ACL时建议把默认用户调成“禁用重命令”的状态:
code复制user default on >AdminStrongPass@2024 +@all -config -shutdown -flushall -flushdb
这行配置的意思是:默认用户允许执行所有命令,但排除掉 config、shutdown、flushall、flushdb 这几个高危操作。就算是管理员误操作或者攻击者拿到密码,也没法直接清库或重启服务,必须配合其他手段才能实现破坏。
我自己的习惯是:读写分离的服务各建一个ACL用户,只读用户给报表和监控,读写用户给业务应用,管理员账号单独保存,日常排查用只读账号。压力测试场景才临时用管理员账号调整配置,用完立刻下线。这样即使某个应用的配置泄露,也不会把整个Redis实例的管理权限拱手让人。
设置Redis访问密码这件事,从表面看只是一个配置项,但真正做扎实了,牵扯到默认安全边界、配置加载方式、客户端连接链路、主从复制、ACL权限分层等多个环节。我个人在实际操作中体会到的是:每次给Redis加完密码,最好的验证不是检查配置文件,而是直接用 redis-cli 以认证书和非认证书两种方式各打一条命令,确认“不带密码坚决进不去,带密码畅通无阻”。这套基线验证方法很简单,却能在后续接入业务、搭建主从之前把认证问题拦在最前面。最后再多说一句,密码只是个起点,配上ACL、限制好权限、管好配置文件,Redis的安全线才算真正拉起来了。
