ARTICLE DETAIL

资讯详情

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

Redis密码设置全攻略:从requirepass到ACL的安全加固实践

Redis密码设置全攻略:从requirepass到ACL的安全加固实践 1. 为什么Redis默认不带密码却总有人被扫先说个真实经历。前几年我搭过一套内部用的Redis没设密码。当时想得很简单只在内网访问的人就那几个没必要折腾认证。结果第二天收到告警CPU占用飙到100%上去一看Redis里被塞满了挖矿相关的Key/var/spool/cron目录里多出了一个定时任务进程列表里还有几条奇怪的bash在跑。事后复盘特别清楚——就是6379端口被扫到了对方连进来之后通过Redis写了计划任务整个过程不需要任何认证。这个事给我的教训就是Redis默认的状态并不是安全可用而是信任网络环境。官方默认配置里protected-mode yes只会在bind 127.0.0.1且没有设置密码时生效也就是只有本机能够访问。可一旦你改了bind、或者用Docker把端口映射出来、或者服务器在云上开了公网端口这层保护就基本失效了。而requirepass默认是空的什么都没有。所以只要你装了Redis第一件事就应该是考虑怎么设置密码。这不是什么进阶操作而是跟安装配置同等基础的安全底线。下面这套方法我按最常见的使用方式梳理一遍配置文件改法、命令行改法、Windows和Docker环境的差别、客户端连接时的密码处理、主从复制的特殊场景以及Redis 6之后更精细的ACL用户权限怎么用。2. 两种最基本的设置方式配置文件与命令行动态配置给Redis设置密码本质上就是设置requirepass参数。这个参数有两种改法直接改redis.conf或者用CONFIG SET命令动态修改。2.1 改redis.conf重启后依然生效Linux下Redis的配置文件一般位于/etc/redis/redis.conf。打开之后找到这样一行# requirepass foobared默认是被注释掉的。把它改成你的密码即可requirepass YourStrongPassword改完以后重启Redis服务sudo systemctl restart redis这样可以验证密码是否生效redis-cli -a YourStrongPassword ping # 返回 PONG 就代表认证通过如果不加-a直接执行redis-cli ping会看到这样的报错(error) NOAUTH Authentication required.看到这个报错说明认证已经生效只是客户端还没带上密码。有一点必须提醒redis.conf里保存的是明文密码。自己本地测试怎么都行但生产环境一定要把配置文件的权限收严建议chmod 600避免其他系统用户直接读到密码。2.2 用CONFIG SET动态修改无需重启如果你不想重启Redis或者只是想临时测试一下可以在redis-cli里直接设置redis-cli CONFIG SET requirepass YourStrongPassword AUTH YourStrongPassword这里有一个很多人踩过的顺序问题CONFIG SET requirepass执行成功后当前连接本身不会断开你依然可以继续操作。但下一次新建立的连接就必须带密码了。所以AUTH要在CONFIG SET之后执行用来让当前这个会话继续获得认证状态。如果你先执行了CONFIG SET再去敲其他命令同样会报NOAUTH。CONFIG SET只对运行中的实例生效进程一重启就没了。要持久化记得执行CONFIG REWRITE这个命令会把当前运行中的有效配置写回redis.conf包括你刚设置的密码。所以我个人的习惯是先用CONFIG SET在线把密码加上确认无误后立刻CONFIG REWRITE避免改配置文件后忘记重启导致没有生效也避免生产环境直接乱动配置文件引发不必要的重启。2.3 两种方式的对比修改方式生效时机重启后是否保留适用场景修改redis.conf重启后生效保留新装Redis时的初始化配置CONFIG SET CONFIG REWRITE立即生效保留执行REWRITE后生产环境在线变更不想重启CONFIG SET不REWRITE立即生效不保留临时调试、测试实际操作中我建议两条路都掌握。有时候你在内网临时拉个Redis做测试没必要动配置文件直接在线设置密码就够了。但要长期跑的服务一定要保证密码落到配置文件里否则哪天进程被重启Redis又会变成无密码状态——这种事故我见过不止一次。3. Windows、Linux和Docker环境下设置密码的实操差别不同环境下配置文件的位置、启动方式甚至配置文件名都不一样。这部分最容易踩的坑不是密码本身而是你改了配置但服务加载的根本不是这个文件。3.1 Linux下最标准的路子Linux下以systemd方式运行的Redis配置修改后重启即可。比较需要注意的一点是先确认当前实例加载的配置文件路径再动手改。用这个命令看redis-cli CONFIG GET dir这个命令返回的是Redis的工作目录不是配置文件路径。想确认配置文件本身通常看进程参数。ps -ef | grep redis # 例如 /usr/bin/redis-server 127.0.0.1:6379这样能看到启动命令有没有显式指定配置文件。有些发行版会默认加载/etc/redis/redis.conf有些老版本安装方式则是手动编译后启动时带一个6379.conf。改错文件是这类问题里最高发的错误。3.2 Windows下部署Redis的特殊处理Windows没有官方Redis版本我一般用的是 tporadowski/redis 这个开源编译版本或者微软Archive里的老版本。Windows版Redis的配置文件叫**redis.windows.conf**不是redis.conf这点很多新手直接懵。启动时要显式指定配置文件redis-server.exe redis.windows.conf如果你不加配置文件直接运行redis-server.exe它会按默认配置启动你改的redis.windows.conf根本没被加载。设了密码不生效大概率就是这个原因。如果你把Redis注册成了Windows服务还要检查服务的启动参数是否包含了配置文件路径。我在Windows服务管理器里见过很多次服务命令行是D:\Redis\redis-server.exe后头什么都没带配什么密码都白搭。手动改成D:\Redis\redis-server.exe D:\Redis\redis.windows.conf然后重启服务。Windows版Redis还有一个让人头疼的点版本普遍偏老。如果你用的Redis 5.xACL功能就不存在只能靠requirepass。所以Windows环境里别一上来就想着用ACL先把最基本的密码加上才是正道。3.3 Docker容器设置密码Docker方式安装Redis设置密码最直接的方式是在启动命令里传参docker run -d --name redis \ -p 6379:6379 \ redis:7.2 \ redis-server --requirepass YourStrongPassword注意官方Redis镜像的默认启动命令是redis-server所以当你传自定义参数时要显式带上redis-server。如果写成docker run ... redis:7.2 --requirepass xxx容器会尝试把--requirepass当作可执行文件执行直接报错启动失败。如果你用挂载配置文件的方式docker run -d --name redis \ -p 6379:6379 \ -v /myredis/conf/redis.conf:/usr/local/etc/redis/redis.conf \ redis:7.2 \ redis-server /usr/local/etc/redis/redis.conf那么在配置文件里写好requirepass即可。这里要提醒一个常见的误区官方Redis镜像并没有REDIS_PASSWORD这个环境变量。很多第三方镜像比如Bitnami的Redis镜像才支持REDIS_PASSWORD环境变量。你把官方镜像配上REDIS_PASSWORD去启动Redis根本不读这个变量密码自然没生效。网上不少教程混着写建议用之前先确认镜像来源。3.4 改了密码却不生效的排查思路如果你设置了密码但无论怎么连都不要求认证按这个顺序排查检查项操作当前实例加载了哪个配置文件ps -ef看启动参数配置文件里有没有requirepassgrep requirepass /path/to/redis.conf配置里面是否被注释去掉行首#Docker容器挂载是否正确docker inspect看Mounts映射进程重启过没有修改配置文件后需重启或CONFIG REWRITE是否有启动脚本覆盖参数检查systemd unit文件里的ExecStart追加参数这套排查链路我实践下来能解决九成以上的密码不生效问题。4. 设完密码之后客户端、可视化工具和SDK怎么连密码设置完成后你的所有访问方式都要跟着改。这一节把最常见的几种连接方式挨个说一遍。4.1 redis-cli的两种认证写法第一种是启动时带密码redis-cli -a YourStrongPassword简单直接但有个副作用密码会出现在shell的进程列表里如果你是在共享机器上执行别人用ps -ef就能看到密码。更稳妥的做法是用环境变量export REDISCLI_AUTHYourStrongPassword redis-cli这样既不用每次敲-a也能避免密码直接暴露在进程参数里。这是Redis官方支持的一种方式日常使用非常顺手。第二种是进入交互模式后再认证redis-cli AUTH YourStrongPassword适合临时连接或者脚本里先连接再做认证的场景。需要特别注意的是如果密码里包含、$、#这类特殊字符用-a参数直接传的话shell可能会做变量展开或截断建议统一用环境变量方式省心很多。4.2 可视化客户端怎么填现在使用频率比较高的是Another Redis Desktop Manager。连接配置很简单地址填IP或域名端口填6379密码填你设置的requirepass值测通即可。如果你用老的Redis Desktop Manager遇到连不上不要先怀疑密码。Redis 6.0之后ACL机制的引入让旧版Redis Desktop Manager在部分场景下会出现密码正确但认证失败的问题。这个问题我处理过好几次要么换新版要么直接换Another Redis Desktop Manager。还有一个排查技巧命令行先试通再去填工具参数这样能快速区分是Redis侧的问题还是客户端工具的问题。4.3 常用语言SDK的密码配置Python的redis-pyimport redis r redis.Redis( hostlocalhost, port6379, passwordYourStrongPassword, decode_responsesTrue ) print(r.ping())Java的JedisJedis jedis new Jedis(localhost, 6379); jedis.auth(YourStrongPassword); System.out.println(jedis.ping()); jedis.close();Go的go-redisrdb : redis.NewClient(redis.Options{ Addr: localhost:6379, Password: YourStrongPassword, }) pong, err : rdb.Ping().Result() fmt.Println(pong, err)这些SDK的认证逻辑本质都一样建立TCP连接后发送AUTH命令。如果密码错误Python 的redis-py会抛出AuthenticationErrorJava会收到NOAUTH相关的异常信息Go的err非nil。错误信息本身并不统一排查时不要死盯SDK异常回到redis-cli验证是最快的路径。4.4 认证对性能的影响有人担心加了密码会拖慢Redis性能。实际上认证只在连接建立时发生一次握手完成后后续命令走的是TCP长连接完全不受影响。连接池模式下一条连接认证一次后续复用即可基本可以忽略这个开销。但连接池里有个小坑如果某个连接因为密码错误被Redis拒了有的连接池不会自动丢弃这个坏连接会反复抛出认证异常。遇到这种情况先把密码改对然后重启应用或清空连接池。5. 主从复制与哨兵模式下设置密码容易踩的坑单机Redis设置密码很简单一旦涉及主从复制、哨兵模式坑就来了。最常见的问题是主库设了密码从库同步直接报错。5.1 从库要配置masterauth主库开启requirepass之后从库去同步时会被要求认证日志里会出现类似这样的信息Master induced authentication error解决方法是在从库的配置文件里加上主库的密码masterauth YourStrongPassword这样从库向主库发起同步时就会自动携带认证信息。如果你用的是命令行方式可以这样redis-cli -p 6380 CONFIG SET masterauth YourStrongPassword CONFIG REWRITE这里有一个很多人忽略的细节主从节点最好都设置requirepass并配置相同的masterauth。从库设置密码是为了防止有人直连从库读取数据尤其当你把从库用于只读查询时这个防护很重要。5.2 哨兵模式的认证配置如果用了Sentinel哨兵做高可用哨兵本身也需要认证来连接主库和从库。在哨兵配置文件里要加这么一行sentinel auth-pass mymaster YourStrongPasswordmymaster是主库组的名字YourStrongPassword是主从节点使用的密码。没有这一行哨兵会发现不了主库宕机或者在failover投票后无法完成切换。我实际遇到过的故障场景是主库和从库配置了密码哨兵没配auth-pass结果主库挂了之后哨兵迟迟不执行故障转移整个服务在监控上看起来一切正常但写操作全都失败。排查小半天才发现哨兵根本连不上主库认证失败后就认为主库仍然存活。这个坑不踩一次是真的难以注意到。5.3 集群模式下密码一致性如果用的是Redis Cluster集群模式所有节点的requirepass和masterauth必须保持一致。因为集群内节点之间会互相通信如果某个节点的密码和其他节点不一致它会被其他节点视为不健康节点轻则警告重则被踢出集群。我之前见过一个测试集群其中一个节点被人手动改过密码结果集群状态一直显示fail找半天才发现是密码一致性导致的。配置集群时我的建议是通过统一配置管理工具下发不要手工逐个改否则漏一个节点就容易出这种隐性故障。6. 从requirepass到ACL更精细的用户权限控制Redis 6.0引入了ACLAccess Control List你可以把它理解成Redis自己的用户系统。相比requirepass这种全局限定一个密码的模式ACL能做到不同用户不同权限、不同用户只能访问不同Key。6.1 requirepass的局限requirepass的本质是只有一把钥匙通了就能执行所有Redis命令。这在单人单项目的内网环境够用但一涉及团队协作问题就来了所有人都用同一个密码你没法区分谁做了什么操作也没法限制某个使用者只能读不能写。ACL解决的就是这类问题。6.2 用ACL创建受限用户在redis-cli里执行AUTH YourStrongPassword ACL SETUSER devuser on devpass123 ~* read这行命令创建了一个名叫devuser的用户on表示启用该用户devpass123设置该用户的密码~*允许访问所有Key~是Key模式的通配符read只授权读类命令比如GET、MGET、STRLEN等再创建一个可读写的用户ACL SETUSER writeuser on writepass456 ~* read writewrite授权写类命令比如SET、DEL、INCR等。之后用devuser连接时执行SET foo bar会被拒绝报错NOPERM this user has no permissions to run the set command这就是ACL的核心价值密码从全局一把钥匙细化成了每个用户各自的权限。ACL配置需要持久化执行ACL SAVERedis会把ACL配置写入配置文件或单独的aclfile。具体写在哪个文件由配置里的aclfile参数决定。如果你不执行ACL SAVE重启后ACL配置会丢失只保留配置文件里的requirepass。6.3 requirepass和ACL的关系看到这里你可能会有疑问requirepass和ACL能不能混用其实requirepass本质上是在给ACL中的default用户设置密码。你设置了requirepass等价于给default用户加了一个密码。当你再用ACL SETUSER修改default用户的密码时效果和改requirepass是一样的。生产环境我建议这样处理要么只用requirepass守住入口要么完全切换到ACL的default用户加自定义用户。两种机制别混着反复设置不然你很难判断当前连接的认证状态到底由哪边控制。对于老项目requirepass够用对于新项目尤其是有多团队复用Redis的场景直接上ACL后续再扩权限会从容很多。另外说一句如果你是Windows上的老版本RedisACL基本不用考虑因为Redis 6.0才引入ACL而Windows编译版普遍停在Redis 5.x。老老实实用requirepass就行。7. 密码之外的加固组合别让密码形同虚设设置密码只是第一步。如果其他基础安全没做密码再强也可能挡不住。7.1 密码本身怎么选Redis的密码不像网站登录密码需要频繁输入所以完全没必要为了好记而设成123456或者redis。我见过真有生产环境把密码设成redis的被扫进去是迟早的事。建议至少12位大小写字母、数字、特殊字符混合。因为Redis客户端连接本来就是长连接密码再长也就输一次不存在体验问题。还有一个安全细节不要把密码提交到Git仓库。我见过有人在config目录里直接写了测试密码然后随项目一起提交这种隐患比密码弱还麻烦。配置文件里涉及密码的最好加到.gitignore或者用模板替换的方式管理。7.2 我建议的生产环境加固组合requirepass或ACL用户认证确保所有访问方必须认证protected-mode yes不要随手关掉bind限定访问源IP比如只允许应用服务器IP访问云服务器安全组和Linux防火墙双重限制6379端口只放行必要来源Redis运行账户使用独立低权限用户不要用root运行重命名高危命令比如CONFIG、FLUSHALL、SHUTDOWN降低被入侵后的破坏半径rename-command CONFIG rename-command FLUSHALL rename-command SHUTDOWN 这条配置在旧版本Redis里很有用。如果使用ACL可以更精细地直接不给相关用户授权这些命令比rename更清晰。7.3 常见故障排查速查表故障现象诊断思路解决方案连接时报NOAUTH Authentication required客户端没带密码或密码为空客户端配置密码执行ping也报NOAUTH当前会话未认证执行AUTH 密码密码正确但连接失败客户端版本太老不支持ACL换客户端或升级版本主从同步中断从库缺少masterauth配置masterauth哨兵不触发故障转移哨兵缺少auth-pass配置配置sentinel auth-passDocker启动后密码不生效配置文件未加载或镜像不支持环境变量显式传参或挂载配置文件重启后密码丢失用的是CONFIG SET但没CONFIG REWRITE执行CONFIG REWRITE最后再分享一个小习惯每次修改完Redis认证配置后我会用一条命令做体检确认当前实例的认证状态符合预期redis-cli -a $REDISCLI_AUTH -h 127.0.0.1 --no-auth-warning INFO server | grep redis_version去掉密码后同样执行一遍应该看到NOAUTH报错。这能快速确认带密码能通、不带密码不通这个最基本的预期也方便后面排查客户端问题时有一个明确的对比基准。在生产环境里我建议你在第一次部署Redis时就顺手把密码加上比事后补救轻松得多——这句话是真的从被扫的教训里学来的。
返回列表