ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Redis密码配置实战:从requirepass到ACL的完整安全指南

Redis密码配置实战:从requirepass到ACL的完整安全指南 说个真实经历。前几年我接手过一套测试环境Redis装在云服务器上端口直接暴露在外网连密码都没有。刚开始没人当回事直到某天早上监控报警数据库里的 key 被删得干干净净只剩一个叫“please_pay_btc”的 key——被人写入勒索信息了。还好是测试库但这事儿给我的教训特别深Redis 设置密码这件事儿从来就不是“可选项”而是上线之前的必选项。这篇文章就围绕“Redis 如何设置密码”这条主线把三种常见部署方式的配置方法、客户端连接验证、我踩过的坑、以及从 requirepass 到 ACL 的进阶玩法一次说清楚。我尽量不写那种“官方文档翻译”式的复读而是把日常运维里真正会用到的场景、命令和判断思路讲明白。如果你是刚接触 Redis 的新人看完至少能把密码配上去跑通全链路如果你已经有一定经验重点可以放在第 4、5 部分的排错思路和 ACL 实践上。1. 为什么要给 Redis 设置密码不只是“官网推荐”这么简单1.1 无密码 Redis 的“裸奔”风险面很多人觉得 Redis 只是内网服务设置密码多此一举。但实际上 Redis 默认监听 0.0.0.0:6379在不少初始化安装脚本里bind 配置要么被注释掉要么是默认的全网监听。只要这台机器有公网 IP 或者防火墙规则没收紧外网直接就能连上来执行命令。没有密码意味着什么攻击者只需要三步连上端口、发一个FLUSHALL、写入一段勒索文案。早年 MongoDB、Elasticsearch、Redis 这三类服务的“勒索挖矿”事件里Redis 是最典型的被刷屏对象。原因很简单它太容易进来了默认无认证、命令强大、数据还能被清空。更麻烦的是Redis 里如果开着危险命令而密码没设攻击者还能通过CONFIG SET dirCONFIG SET dbfilename组合写文件甚至在某些权限配置不当的服务器上拿到 webshell。我见过不止一次因为 Redis 裸奔导致整个主机被入侵的案例最后追溯下来根因就是“我 Redis 就内网用一下没设密码”。设置密码并不能解决所有安全问题但它是最基础的一道门禁。先把门锁装上再谈后面的防火墙、绑定 IP、最小权限这些纵深防御。1.2 requirepass 的认证流程AUTH 命令怎么运作Redis 的密码验证机制在 6.0 之前主要靠requirepass配置项实现。这个配置项在 redis.conf 里默认是被注释掉的。一旦你设置requirepass yourpasswordRedis 就进入了“需要认证”模式所有未认证的客户端都会收到NOAUTH Authentication required.错误。客户端能做什么两条路一是连接后主动发送AUTH yourpassword二是部分客户端会在连接参数里直接带密码由客户端库在握手阶段自动完成认证。从服务端视角看Redis 只会在收到AUTH命令后校验密码是否正确。校验通过这个连接就被标记为“已认证”后续命令正常执行。这里有个容易被忽略的点Redis 的密码校验只在连接建立阶段发生一次不会对每条命令做重复校验。也就是说认证的开销几乎可以忽略不计。这也是为什么 Redis 官方敢说“密码验证对性能影响极小”——它不像某些数据库那样每条 SQL 都要做二次鉴权。我实测过在压测场景下开启 requirepassQPS 的波动范围基本在误差以内。1.3 Redis 6.0 之后的新变化ACL 与 requirepass 的关系Redis 6.0 引入了 ACLAccess Control List把“输入密码就行”升级成了“用户名 密码 权限集合”。在 ACL 模式下默认用户default就相当于原来的 requirepass你可以继续使用requirepass给 default 用户设置密码也可以用ACL SETUSER创建多个独立用户。这意味着什么从 6.0 开始密码设置从“一把钥匙开一扇门”变成了“多把钥匙开多扇门”。比如开发环境里你可以给数据部门定义一个只读用户给运维定义一个可执行CONFIG命令的超级用户给应用服务定义一个只操作特定 key 前缀的普通用户。每个用户用各自的密码登录互不干扰。不过需要提醒的是如果你升级 Redis 到 6.0 以上并且还继续用旧的requirepass方式它在绝大多数情况下依然有效。只有当你执行了 ACL 相关命令后default 用户的认证才会切换到 ACL 模式这时候原来通过requirepass设置的密码可能与 ACL 里 default 用户的密码产生不一致的情况。我在第 4 部分会专门讲这个坑。2. 三种部署环境下的密码配置实操2.1 Linux 环境修改 redis.conf 的正确姿势最常见的部署方式就是 Linux 服务器上装 Redis。不管你是通过 apt/yum 安装还是编译安装最终都要落到配置文件上。Redis 在 Linux 下的默认配置文件通常叫redis.conf常见路径有/etc/redis/redis.conf、/usr/local/etc/redis.conf或者 Redis 安装目录下的根目录。操作步骤我梳理成三步第一找到配置文件。使用redis-cli info server能看到config_file字段直接告诉你当前实例加载的是哪个配置文件。这一步非常重要因为多人维护的机器上可能同时存在好几份 conf 文件你改了不生效的那份后面就等着重启时怀疑人生。第二修改 requirepass。打开配置文件找到这一行# requirepass foobared去掉前面的#把foobared换成自己的强密码。比如requirepass MyStrongPassword_2024!第三重启 Redis 服务让配置生效。sudo systemctl restart redis或者如果你是用源码启动的直接停掉进程再用redis-server /path/to/redis.conf启动。重启后用redis-cli -a MyStrongPassword_2024! ping验证一下能返回PONG就说明认证通过了。注意如果运气不好重启后还是一切照旧、没有要求输密码多半是配置文件路径搞错了。先执行redis-cli CONFIG GET requirepass看看当前生效的密码是什么再对照上面config_file字段检查加载路径。2.2 Windows 环境redis.windows.conf 和命令行启动差异Windows 上玩 Redis 稍微特殊一点。官方其实不提供 Windows 原生版本大家用的基本都是微软以前维护的移植版或者 Redis 官网列表里那个 Memurai 这类第三方发行版。所以 Windows 下没有/etc/redis.conf这种路径而是redis.windows.conf。在 Windows 上给 Redis 设置密码最常见的有两种路径第一种修改配置文件。在 Redis 解压目录里找到redis.windows.conf同样找requirepass项。这文件名容易让人混淆注意不是redis.conf——如果你用redis-server.exe redis.windows.conf启动系统加载的其实是后者。很多人改了redis.conf没反应就是因为 Windows 发行版默认文件名不叫这个。第二种命令行参数直接指定。如果你只是临时起一个实例不想动配置文件可以直接redis-server.exe --requirepass MyPass这种方式的好处是快坏处是密码会出现在进程命令行里某些监控工具能直接看到。建议临时测试用行长期使用还是写进配置文件里。Windows 下还有个易错点配置文件里中文路径和特殊符号转义。比如密码里带!或$在 PowerShell 启动时可能会被解析成特殊含义记得用单引号包起来。我在 Windows 上踩过$被 PowerShell 当成变量展开的坑明明配置文件里是对的启动时命令行一传参就变了。2.3 Docker 部署临时参数和配置文件挂载两种方式现在很多人用 Docker 跑 Redis密码设置又回到两种流派一条命令搞定和配置文件挂载。一条命令搞定的方式docker run -d --name redis \ -p 6379:6379 \ redis:7.2 redis-server --requirepass MyDockerPass这种方式适合快速起一个开发实例。但问题是一旦容器被删除重建密码配置就没了。而且--requirepass直接写在 docker run 命令里容易被docker inspect看到严格来说不算安全。更推荐的方式是准备一份自己的 redis.conf通过挂载传进容器docker run -d --name redis \ -p 6379:6379 \ -v /opt/redis/conf/redis.conf:/etc/redis/redis.conf \ redis:7.2 redis-server /etc/redis/redis.conf这样配置文件跟容器生命周期解耦密码、持久化策略、绑定地址都统一管理。如果用的是 docker-compose看起来更清晰services: redis: image: redis:7.2 container_name: redis ports: - 6379:6379 volumes: - /opt/redis/conf/redis.conf:/etc/redis/redis.conf command: [redis-server, /etc/redis/redis.conf]我个人的经验是容器化环境更应该用配置挂载否则每次版本升级、容器重建都容易把安全配置弄丢后面出现“怎么容器都换了一轮密码反而没了”的情况。3. 密码生效验证与全链路连接配置3.1 先用 redis-cli 验证密码是否生效配置完密码第一件事就是用命令行验证。不要直接跳到应用侧去调接口否则你会分不清到底是密码问题、网络问题还是编码问题。最简单的验证流程# 不带密码连接 redis-cli -h 127.0.0.1 -p 6379 ping # 预期输出NOAUTH Authentication required. # 带密码连接 redis-cli -h 127.0.0.1 -p 6379 -a MyPass ping # 预期输出PONG第一行如果返回了NOAUTH说明密码已经生效第二行返回 PONG 说明密码正确。这里有一个很多人不知道的小细节当密码错误时Redis 返回的不是PONG而是ERR invalid password。如果你看到这个先别急着怀疑客户端大概率就是密码输错了。另外注意-a参数在进程列表里是明文可见的在共享服务器上操作时尽量不要用这种方式可以用--no-auth-warning屏蔽一下警告或者干脆先进入交互模式再输入 AUTH。3.2 应用侧连接Spring Boot 配置为例服务端验证完了就得改应用侧连接配置。以 Java 生态最常见 Spring Boot 为例如果用的是 spring-boot-starter-data-redis那么在application.yml里加上密码spring: redis: host: 127.0.0.1 port: 6379 password: MyPass timeout: 3000ms如果你的应用用到了 Redis Cluster 或者 Lettuce 连接工厂配置方式基本一致。这里有个实际工作中经常犯的错很多老项目之前没配密码后来 Redis 加密码了但 Spring Boot 的配置中心里只改了一台环境的密码其他环境漏改。结果就是生产环境一切正常测试环境一启动全部报NOAUTH或者RedisConnectionException。另外密码中含特殊字符时比如#、:、这些在 yml 文件里建议用引号包起来spring: redis: password: MyPass#2024否则 YAML 解析器可能把#当成注释开头导致密码被截断。这个问题非常隐蔽我一度以为是 Redis 服务端的问题排查到最后发现是配置语法。3.3 可视化客户端连接RDM / AnotherRedisDesktopManager日常开发里大家经常用可视化客户端摸数据比如 Redis Desktop Manager现在叫 RESP.app、Another Redis Desktop Manager 这些。连接配置里无非也就是填主机、端口、密码三项。有一个细节值得说很多可视化工具在“密码”这一栏留空时默认走无认证但如果 Redis 设置了密码它们会在连接时自动弹一个认证失败的错误。这不代表工具不好用而是提醒你要去检查地址栏左侧的“Auth”选项。部分工具还支持在 URL 里直接带密码比如redis://:passwordhost:port这种格式但注意密码里如果包含特殊字符要做 URL 编码要转成%40否则解析会出错。我平时用的习惯是先在命令行验证一遍密码再用可视化工具连避免工具界面上的错误信息干扰判断。可视化工具连不上时第一反应先redis-cli ping能通就是工具配置问题不能通就是服务端网络或密码问题。3.4 命令行的 -a 参数方便但“高危”很多教程为了让新手快速看到效果喜欢用redis-cli -a password这种写法。我必须提醒这个-a参数在 Linux 下会出现在ps进程列表里如果服务器有别的用户或者被监控系统记录相当于密码直接暴露了。更稳妥的方式是利用环境变量export REDISCLI_AUTHMyPass redis-cli pingRedis 的 CLI 工具支持从REDISCLI_AUTH环境变量读取密码这样不会出现在命令行缓冲区里。还有一个选择是在交互模式下手动输入redis-cli 127.0.0.1:6379 AUTH MyPass OK 127.0.0.1:6379 PING PONG交互模式下密码不会出现在进程列表里。虽然麻烦一点但在多人共用的机器上这是最安全的方式。4. 我踩过的坑常见问题与排查清单4.1 改了配置重启后不生效这是出现频率最高的问题没有之一。多半是配置文件改错位置了。Redis 启动时加载哪个配置文件不是看它在哪而是看启动命令里有没有指定。大多数 Linux 发行版通过 systemd 启动时都有各自的配置文件参数比如 CentOS 上默认加载/etc/redis.confUbuntu 上可能是/etc/redis/redis.conf。排查思路很简单# 查看当前生效的配置文件路径 redis-cli -a YourPass CONFIG GET config_file如果这条命令报NOAUTH说明当前配置已经加了密码但你还没输密码如果没有报错说明 Redis 还在裸奔配置文件压根没加载成功。此时检查 systemd 服务文件里ExecStart参数是否明确指定了配置文件。另外一个坑是你改了配置文件但 Redis 进程没真正重启只做了systemctl reload。Redis 对reload的支持和某些服务不一样很多时候只是重新读取部分配置requirepass 这类参数未必会热加载。我的经验是改 requirepass 后直接 restart 最稳。4.2 设置了密码后主从复制不同步了这是一个特别经典的问题。你在主库上设置了 requirepass但从库没有感知到认证信息于是从库连接主库时被拒绝表现为MASTER - REPLICA sync started之后一直error日志里反复刷NOAUTH Authentication required.原因在于 Redis 复制同步是主从之间单独建立的连接。主库有密码后从库必须用masterauth配置项指定“我连主库时用哪个密码”。这个配置写在从库的配置文件里masterauth MyMasterPass注意这不是指从库自身的密码从库自身认证由它自己的requirepass决定masterauth是专门给复制链路用的认证口令。很多人在这里搞混给从库配了requirepass却不配masterauth最后从库一直连不上主库。如果你用的是 Redis Cluster情况类似。每个节点上的 master 和 slave 之间的复制也需要masterauth。在创建集群之前最好就把masterauth写进配置文件否则后面节点角色一切换新提升的 master 也可能因为认证信息缺失导致复制中断。4.3 密码里带 $ 或 ! 特殊字符导致连接失败我给测试环境设密码时习惯用!结尾觉得这样“更强”。结果 Spring Boot 连接一直报Unable to connect to Redis但用 redis-cli 又能连上。排查到最后发现是 YAML 配置里密码没有用引号包裹!被 YAML 解析器当成了特殊标记符实际传给 Redis 的密码被截断或改变了。这类问题的排查思路先看配置里密码值到底是什么再看服务端实际接收到的密码是什么。一个技巧是在 Spring Boot 启动日志里临时打印一下 Redis 连接工厂的配置信息看 password 字段有没有被解析正确。只要保证 YAML 里用单引号或双引号把密码包住基本就能避免。另外如果密码里有$在 Linux shell 里被当成变量展开也要注意。echo My$Pass和echo My$Pass输出完全不一样。凡是在命令行里传密码的操作我都建议用单引号包裹或者用环境变量避免被 shell 解析。4.4 升级到 Redis 6 后ACL 与 requirepass 冲突说这个我之前先讲个故事。有台机器原本用的 Redis 5用requirepass oldpass做认证。某次运维升级到 Redis 7启动时发现原来的密码失效了但配置文件里明明还写着requirepass oldpass。怎么AUTH oldpass报错了原因在于 Redis 6 启用 ACL 后如果配置里也没有显式定义 ACL 用户系统会创建一个默认用户。这个默认用户的密码可能被初始化成了其他值或者受aclfile配置影响导致requirepass和 default 用户的密码不一致。更隐蔽的情况是配置里既有requirepass又在启动时执行了ACL SETUSER相关命令后者的修改会把前者覆盖掉。处理办法是统一管理要么回到纯 requirepass 模式不启用 ACL仅在配置里写requirepass要么完全切到 ACL 模式用aclfile定义用户和密码不再使用requirepass。不要两个概念混着用不然排查起来真的很费劲。4.5 忘记密码之后的紧急恢复流程这个场景每个运维都可能遇到。Redis 密码不知道、但又要尽快恢复服务怎么办思路很简单绕过认证。Redis 只有在配置了requirepass后才会强制认证所以我们只需要修改配置文件让 Redis 临时以无密码模式启动然后再重置密码。具体步骤停止 Redis 服务。sudo systemctl stop redis把配置文件里的requirepass一行注释掉或临时改成一个空值。启动 Redis。此时 Redis 不强制认证直接就能连上。用CONFIG SET临时设置新密码redis-cli CONFIG SET requirepass NewPass用CONFIG REWRITE把当前配置写回配置文件redis-cli -a NewPass CONFIG REWRITE这样密码就持久化了。最后记得把第 2 步改掉的内容检查一遍确保配置文件里已经有正确的密码或重新把注释恢复。注意这个操作只适用于你有服务器文件系统访问权限的场景。如果连物理机都进不去那就只能走云厂商的控制台或工单流程了。5. 从 requirepass 到 ACL更细粒度的访问控制5.1 requirepass 的三个明显局限requirepass 虽然简单但它的局限也摆在脸上。第一它是“全局单密码”所有人所有应用都共用一个密码。只要一个人泄露等于全库暴露想单独回收某个应用的权限也做不到。第二它只有“认证”功能没有“授权”功能。只要密码正确这个连接就能执行任何操作包括FLUSHALL、CONFIG、SHUTDOWN这些危险命令。第三它在多团队协作时没有审计能力无法区分“谁”执行了那条危险命令对安全审计很不友好。在只有一台开发机、几个开发者自己玩的情况下requirepass 够用。但一旦 Redis 承载的是线上业务或者有多个应用、多个部门同时使用ACL 就值得认真考虑了。5.2 ACL 快速上手创建一个只读用户Redis 6.0 之后ACL SETUSER命令可以把“用户、密码、权限”绑定在一起。比如我想创建一个名叫reader的用户密码是readpass只能执行读命令不能执行写命令和危险命令。ACL SETUSER reader on readpass ~* read我来拆解一下这段命令的意思。on表示启用该用户readpass是设置密码~*表示该用户可以访问所有 key 模式read是添加读命令类别。如果想要更严格一点可以把~*换成~cache:*这样该用户只能读取cache:前缀的 key。创建完之后需要验证一下redis-cli --user reader --pass readpass 127.0.0.1:6379 GET cache:foo (nil) 127.0.0.1:6379 SET cache:foo bar (error) NOPERM this user has no permissions to run the set command看到NOPERM就说明权限限制生效了。5.3 ACL 规则速查与配置持久化ACL 规则看着复杂但核心就几个符号规则片段含义on/off启用 / 禁用该用户password设置新密码password删除密码~pattern允许访问的 key 模式category添加命令类别权限如read、write-category移除命令类别权限command允许某条具体命令如get-command禁用某条具体命令如-flushallallkeys/allcommands等价于~*/all放开全部ACL 配置可以写在 redis.conf 里也可以单独指定 aclfile。我个人的建议是如果在 Redis 6 上正式启用 ACL不要再用requirepass而是把 ACL 用户统一写进一个 aclfileuser default on DefaultPass ~* all admin on AdminPass ~* all config reader on ReadPass ~cache:* read然后在 redis.conf 里加一行aclfile /etc/redis/users.acl之后修改用户权限时用ACL SETUSER在线调整再ACL SAVE把当前规则写回 aclfile。这样既满足在线变更又能在重启后保留配置。5.4 ACL 的核心思路默认拒绝还是默认放行在配置 ACL 用户的时候我建议默认拒绝只给最小权限。这个思维方式跟防火墙的“白名单”是一致的。你可以先创建一个只有读权限的用户给 BI 团队再创建一个只能写入特定 key 前缀的用户给业务服务对于需要执行CONFIG、SHUTDOWN、FLUSHALL这类命令的单独建一个管理员账号并且严格限制能登录的 IP。这里特别想强调ACL 不只是“多用户密码”同时是对危险命令的断路器。Redis 的命令分类很细admin、dangerous这些类别是专门标记高危操作的。一般业务应用完全不需要这些权限只要你用了 ACL就算密码泄露攻击者也只能做该用户权限内的事。这是 requirepass 永远给不了的。6. 我在实操中的最后一点建议从最早的 Redis 2.x 一路用到现在的 Redis 7.x我自己的习惯经历了几次转变。最开始我也是用requirepass一把锁挂所有实例后来开始引入 ACL给不同业务方分配不同用户。对这个过程我的建议是不要在线上搞“突然切换”先把 ACL 用户建好、权限验证好再加到配置里测试跑一段时间最后再把requirepass注释掉这样最稳。还有一个细节很多人忽略设置密码后redis-cli -a每次都会打出一行警告Warning: Using a password with -a ... is insecure。这不是报错是刻意设计的提醒。如果你用的是 CI/CD 自动化脚本建议把密码放到环境变量或密钥管理服务里不要在 Jenkins 任务中明文写死。Redis 设置密码这件事说起来只有一行配置但做起来牵扯配置文件、客户端、主从复制、容器部署、权限模型好几个层面。希望这篇内容能帮你把这条链路走通少走我当年走过的弯路。如果后续遇到 ACL 更细粒度的权限设计问题欢迎一起交流。
返回列表