Redis 又上热搜了。每次有人在安全群里喊"Redis被批量打穿"的时候,评论区总会出现同一个问题:"我就是装了Redis,怎么判断自己中没中招?"说实话,这个问题挺难回答,因为很多人连自己的Redis已经成了攻击者的"肉鸡"都没察觉——端口6379开着、requirepass没配、bind 127.0.0.1还躺在注释里,这类情况我每隔一段时间就能在生产环境里撞见一次。
这篇文章我打算换个角度聊,不堆CVE编号,而是把Redis漏洞这件事从头到尾拆开:它为什么隔三差五出现在漏洞报告和热搜词里、真实攻击者是怎么一步步得手的、我们做防御的人应该如何复现和验证这条链路、最后生产环境到底该怎么加固才能把自己从"漏洞重灾区"里拎出来。无论你是运维、开发还是刚入门的安全新人,顺着这条线走一遍,你至少能搞清楚一个核心问题:Redis的安全水位,到底是靠什么撑起来的。
1. 为什么Redis总出现在漏洞榜上:设计基因里的几道暗门
Redis被点名不是一两年的事了。从早期爆出的未授权访问,到后面的主从复制RCE,再到各种配合弱口令的批量扫描事件,它的"漏洞体质"其实和它的出身有直接关系。
1.1 未授权访问:被当成默认值的"裸奔"模式
Redis诞生的时候主要跑在内网,开发者默认使用它的人都是可信的。所以你会发现早期的Redis配置非常简单,安装完不做任何设置,它就会监听在所有网卡上,任何能连到6379端口的客户端都可以直接执行命令,根本不需要认证。这个设计放在那个年代没毛病,但放到现在的公网环境里就等于是开着门不锁就出门。
后来官方也意识到问题,加了protected-mode yes这个受保护模式。注意,这个保护模式只在Redis监听了本机回环地址(127.0.0.1)或者没有任何显式bind配置的时候才生效。如果运维手滑把bind 0.0.0.0写在配置里,或者干脆用默认配置不做任何bind,受保护模式在部分场景下是可以被一些手法绕过的。更不用说一堆老版本压根没有这个机制——很多还在生产环境跑着的Redis 3.x、4.x,默认配置依然是"全网裸奔"。
1.2 主从复制机制:功能特性如何被改造成攻击跳板
主从复制本意是好的:主库把数据同步到从库,实现读写分离和高可用。攻击者看中的恰恰是这条链路。Redis 4.0开始支持通过MODULE LOAD加载外部模块,这本来是为了扩展功能,比如加一些自定义数据结构和命令。
但2019年前后被公开利用的"主从复制RCE"思路,就是把这两个特性串起来了:攻击者先让受害Redis执行SLAVEOF,指向自己控制的恶意Redis服务器,然后通过主从同步把一个编译好的恶意模块文件写进受害Redis的数据目录,再通过MODULE LOAD加载这个模块。模块一加载,等于攻击者拿到了一条直接执行系统命令的通道。这个思路之所以经典,是因为它把Redis的"高可用功能"直接变成了"远程命令执行入口"。后来官方在新版本里做了一些限制,但大量存量老实例仍然暴露在风险中。
1.3 弱口令与公网暴露:大多数漏洞事件的共性前提
抛开那些花哨的利用链,我更愿意说一个扎心的事实:我所处理过的大部分Redis失陷事件,根因根本不是0day,而是公网暴露+弱口令。用测绘工具在公网扫一下6379端口,出来的结果能让你头皮发麻。再配合常见弱密码字典跑一遍,能拿到权限的实例数量相当可观。
这也是为什么每次Redis相关漏洞被热炒的时候,总会有一种论调说"这不是Redis的漏洞,是使用方式的问题"。这话有道理,但从防御角度看,只要还有大量裸奔实例存在,Redis就始终是攻击者眼里性价比极高的目标。
2. 一次RedTeam视角的复现记录:从端口扫描到权限落地
说再多理论,不如完整走一遍复现流程。这里我以防御和检测为目的,把攻击链还原出来——不是说教你怎么打,而是让你知道攻击者到底会做什么、每一步留下什么痕迹。读到后面你会发现,几乎所有步骤都有对应的日志和特征。
2.1 情报收集:确认目标是不是"裸奔"的Redis
攻击者第一步不是上来就打,而是做资产测绘。这里常用的就是nmap这类扫描工具,探测目标IP的6379端口是否开放,再通过服务指纹确认是不是Redis。
nmap -p 6379 -sV --script redis-info 目标IP如果返回的信息里有redis_version、redis_mode:standalone这些字段,目标基本可以被判定为Redis服务。还有一种更隐蔽的方式,直接用redis-cli去连,如果能连通并执行INFO,那就是连认证都不需要,直接裸奔。这个阶段的特征是网络层和端口层的探测——很多防守方压根不会关注这个环节的日志。
2.2 未授权访问验证:三种常见的直连探测方式
拿到目标后,攻击者一般会先用客户端直连验证权限。常见的验证方式有三种:
redis-cli -h 目标IP -p 6379直接连,敲INFO看返回。- 用
redis-cli执行CONFIG GET dir,如果返回了路径,说明当前用户有配置读取权限。 - 用可视化客户端,比如AnotherRedisDesktopManager这类工具连接测试,反正一键直连,特别直观。
我在做应急响应的时候,判断一个Redis是不是未授权,基本也是用这三种方式来复验。这里值得多说一句:执行INFO能拿到connected_clients、used_memory、role这些关键信息——如果role显示的不是master而是slave,那就要高度警惕了,很可能已经被攻击者挂到了他们的恶意主库上。
2.3 主从复制利用:加载恶意模块的过程还原
主从复制利用的过程看起来并不复杂:
- 攻击者在自己服务器上起一个Redis实例,作为"恶意主库"。
- 在受害Redis上执行
SLAVEOF 攻击者IP 攻击者端口,让受害Redis变成从库。 - 恶意主库通过主从同步机制,把攻击者预先准备好的恶意.so文件同步到受害Redis的数据目录。
- 在受害Redis上执行
MODULE LOAD /路径/恶意模块.so,加载模块。 - 模块注册一个新命令(比如
system.exec),攻击者直接调用这个命令执行系统命令。
这里的核心逻辑在于:主从同步不仅能同步RDB数据文件,攻击者还可以让受害Redis把同步下来的文件保存成任意文件名,包括二进制模块文件。同步完成后,MODULE LOAD只是最后一脚。
我复现这一步的时候通常用Docker搭两套Redis,一套当攻击者的恶意主库,一套当受害从库,整个过程跑下来不到五分钟。但就是这个不到五分钟的操作,能让攻击者稳稳拿到服务器的命令执行权限。
2.4 利用后的痕迹:这些特征能帮你发现攻击
既然我们做防御,就要知道这些操作会留下什么痕迹:
- Redis日志里会出现
SLAVEOF、MODULE LOAD、CONFIG SET dir这类命令记录,如果开了loglevel notice或warning,大部分会落在日志里。 ROLE和INFO replication会显示role:slave,而且master_host、master_port指向陌生IP。- 用
MODULE LIST能看到当前加载的模块,如果出现不认识的模块名,基本可以实锤被入侵。 - 数据目录下可能出现非RDB/AOF后缀的陌生文件,比如
exp.so、pwn.so之类。
我每次做入侵检测培训都强调一点:Redis不是只能存字符串,它还可以被用来藏模块文件。所以检查的时候,别只盯着key列表看,还得看文件系统、看模块列表、看复制状态。
3. 实战加固清单:把Redis从"漏洞重灾区"拉回安全水位
复现完攻击链,接下来的重头戏是加固。很多文章喜欢把加固写成一条条命令贴出来就完事,但我觉得更值钱的是搞清楚每一层防线到底挡的是攻击链的哪一步。下面按网络层、认证层、命令层、运行层四层来说。
3.1 网络层:bind、防火墙与最小暴露面
绝大多数Redis沦陷案例,第一步都是因为端口暴露到了不该暴露的地方。网络层加固是最便宜、效果最好的一步,也是我建议你第一个去做的。
在redis.conf里,最关键的几项配置:
bind 127.0.0.1 ::1 protected-mode yes port 6379如果Redis只给本机应用用,bind只留本机回环地址就行。如果有多台业务服务器需要访问,就bind到内网网卡IP,不要用0.0.0.0。同时配合云安全组或本地防火墙,只放行来源业务IP的6379端口。
注意一个细节:protected-mode yes不是万能的,它和bind联合使用才有意义。如果你bind了内网IP但没有防火墙规则,内网里其他机器一样能访问。所以网络层的完整语义是:监听地址限制访问来源 + 防火墙兜底限制来源IP。
3.2 认证与权限:从requirepass到ACL的演进
早期Redis只有一个全局密码,就是requirepass。后来从Redis 6.0开始引入了ACL(Access Control List),可以给不同用户分配不同的权限和命令集。这是加固上一个很大的进步,因为你再也不用担心"一个人知道密码,所有命令都能敲"的问题。
基础配置长这样:
requirepass 你的强密码_至少16位以上 # ACL配置示例(Redis 6+) user default off user application on >P@ssw0rd_Prod123 ~cache:* +@read +@write -flushall -flushdb -keys -shutdown -config这里我给了一个比较实用的ACL示例:默认用户关掉,单独建一个application用户给业务用,只允许读写cache:*前缀的key,并且把危险命令全部排除掉。这样即使密码泄露,攻击者拿到一个受约束的账户,能做的事情也极其有限。
关于密码强度,别再用redis123、123456这种了。我在复盘攻击事件时见过太多被字典秒破的案例——弱口令在公网环境里基本等于开门揖盗。
3.3 危险命令治理:禁用、重命名与指令白名单
Redis里有一批命令在业务正常使用中根本用不到,但对攻击者来说却非常关键。典型的几个:
CONFIG:攻击者靠它改配置、开同步、调目录。EVAL/EVALSHA:Lua脚本执行通道,常被用来做数据破坏或信息探测。KEYS:全库key枚举,容易导致数据泄露和性能问题。FLUSHALL/FLUSHDB:一键清空数据,勒索和恶作剧的最爱。SHUTDOWN:直接打停服务。SLAVEOF/REPLICAOF:主从复制入口,主从复制RCE的关键命令。
处理方式有两种,一种是直接禁用,在redis.conf里加:
rename-command CONFIG "" rename-command SLAVEOF "" rename-command REPLICAOF "" rename-command EVAL "" rename-command EVALSHA "" rename-command FLUSHALL "" rename-command FLUSHDB "" rename-command SHUTDOWN "" rename-command KEYS ""另一种是重命名成复杂名字,让攻击者猜不到:
rename-command CONFIG "6f9a2c1b74d8e3f5a1c0"重命名命令的风险是:如果客户端代码里用了原生命令名,重命名后会导致业务报错。所以这条要谨慎评估。禁用命令则更直接,只要业务确认用不到,就明文禁用。
我的经验是:先开审计日志,跑一周看看业务实际调用了哪些命令,再决定禁谁。不要为了安全把业务搞挂了,那也是一种事故。
3.4 运行环境:容器隔离、低权限账号与监控告警
最后一道防线是运行环境本身,很多加固文章会漏掉这部分。
首先是账号权限。不要用root跑Redis,单独建一个系统用户,然后把数据目录的权限锁死:
useradd -r -s /sbin/nologin redis chown -R redis:redis /var/lib/redis其次是容器隔离。用Docker跑Redis是一种比较推荐的部署方式,哪怕被攻击者拿到Redis权限,默认情况下也只是容器内的权限。当然要小心,如果你用--privileged跑容器,或者把宿主的根目录直接挂进去,那隔离就等于破功了。
然后是监控告警。起码要盯几个指标:connected_clients有没有突然暴涨、INFO replication里的角色有没有从master变成slave、进程CPU占用有没有异常飙升。再配合命令审计日志,出了问题能第一时间定位。很多公司是Redis被种了挖矿脚本、CPU100%才发现,那就已经晚了一步了。
4. 溯源与应急:当生产Redis真的被打穿,我如何定位和止损
前面讲的是"怎么防",这一节说"已经被打穿了怎么办"。我做应急响应有一个原则:先止损,再取证,最后才是修复。顺序错了,很可能连证据都没保住。
4.1 发现异常:日志里那些不该出现的命令
最典型的告警信号是从redis.log里看到陌生命令。比如这样一个日志片段:
M 12:43:01.598 * SLAVEOF 192.168.1.100:12345 M 12:43:02.114 * CONFIG SET dir /var/lib/redis M 12:43:02.335 * MODULE LOAD /var/lib/redis/exp.so这三条命令连在一起,基本可以定性:这是一次利用主从复制加载恶意模块的入侵。比这个更隐蔽的还有:通过CONFIG GET *偷配置、批量读key做数据窃取、写入异常key作为后续反弹shell的标记。
但要注意,默认情况下Redis的日志级别是notice,很多命令并不会记录。所以遇到疑似入侵,第一件事就是把日志级别临时调高:
CONFIG SET loglevel debug不过这只是在临时补救,真正的长期方案是开启审计日志,或者在应用层做命令拦截。
除了日志,还有一个很实用的检测方法:MONITOR命令可以实时打印所有执行过的命令。如果Redis已经被入侵、但攻击者的持久化连接还挂着,敲一下MONITOR能看到他在干什么。不过MONITOR本身就消耗性能,线上实例慎用,应急时可以短暂开启。
4.2 溯源链路:从恶意模块回推攻击入口
止损之前要先想清楚一件事:攻击者是从哪进来的?是未授权直连、弱口令爆破、还是走应用层打进来的?方向错了,后面很可能白忙活。
我的溯源顺序一般是:
- 先看
redis-cli能不能免密连上。如果能,那就是未授权访问,入口问题基本实锤。 - 看
redis.log里有没有来自陌生IP的连接记录和危险命令记录。日志里一般能看到Accepting client connection这样的连接记录。 - 看
MODULE LIST和文件系统里有没有陌生模块文件。模块文件的编译时间、文件名往往能提供线索。 - 看系统层面连向6379端口的来源IP,配合防火墙和云安全组日志交叉比对。
这里有个容易被忽略的点:攻击者不一定是从公网进来的,也可能从内网横向移动过来的。如果这台Redis绑定的内网IP,但日志里出现了内网其他机器的IP,那问题可能不只是Redis本身,而是内网别的主机已经失守了。这种情况要做的是全内网排查,而不是只修Redis。
4.3 止损步骤:隔离、清敌、保留证据、恢复业务
一次完整的Redis应急响应,我习惯按这个顺序操作:
- 隔离:先用防火墙或安全组把来源IP封了,再把6379端口对外的访问临时切断。必要的时候,直接把实例停机。这一步是为了阻止攻击者继续操作。
- 保留证据:把
redis.log、redis.conf、数据目录下的可疑模块文件、进程快照都复制出来,存到专门的地方。别在原始环境里直接删文件,那会让取证变得很被动。 - 清敌:打开redis-cli,把攻击者加载的恶意模块卸载掉,恢复主从复制状态,删除恶意写好的key和计划任务。命令大致是:
MODULE UNLOAD exp.so REPLICAOF NO ONE CONFIG SET dir /var/lib/redis CONFIG SET dbfilename dump.rdb注意,卸载模块之前要确认模块名,用MODULE LIST查看。有些恶意模块会注册多个命令,卸载得干净一点。
- 改密与加固:立刻设置或更换
requirepass,启用ACL,禁用危险命令,修改bind和防火墙规则。一句话,把前面加固清单里的内容全部做一遍。 - 恢复业务:确认没有遗留后门之后,再重新开放端口,恢复业务流量。别急着把Redis加回集群,先在低流量状态下观察一段时间,确认没有异常连接再放量。
我在实际项目里遇到过一种情况:攻击者不仅在Redis里加载了模块,还在系统里写了一个定时任务,每五分钟重新执行一次恶意脚本。也就是说,只要你没有清理系统层面的后门,Redis恢复之后很快会被二次入侵。所以应急响应千万别把视野局限在Redis本身,系统级排查同样要做。crontab -l、/etc/ld.so.preload、SSH authorized_keys、启动项这些都要过一遍。
5. 安全之外的延伸:从漏洞看Redis日常使用中的"隐雷"
Redis漏洞本身聊完了,但我觉得有义务再说几句日常使用中容易被忽略的"隐雷"。它们严格来说不是漏洞,但一旦炸了,比漏洞还难受。
5.1 缓存治理:穿透、击穿、雪崩与"漏洞"的概念混淆
Redis最常见的应用场景是缓存。缓存穿透、缓存击穿、缓存雪崩这三个术语,很多人分不清,但它们在运维眼里都是事故级别的存在。
- 穿透:请求的key在缓存里没有,每次都打到数据库,数据库扛不住。
- 击穿:一个热点key过期的一瞬间,大量请求同时打到数据库。
- 雪崩:大量key同时过期,或者Redis直接宕机,流量全部打到数据库,数据库跟着垮掉。
这些虽然不是安全漏洞,但处理不好造成的业务损失比一些漏洞还大。对应手段也很成熟:穿透用布隆过滤器 + 空值缓存,击穿用互斥锁 + 逻辑过期,雪崩用随机过期时间 + 高可用集群。如果你把这些和漏洞话题混在一起讨论,很容易分散精力——安全加固和缓存治理是两件事,都要做,但要分开做。
5.2 分布式锁:锁住的是资源,不是安全
另一个高频词是Redis分布式锁。网上关于分布式锁的文章汗牛充栋,但大部分人没意识到:分布式锁本身就是一把双刃剑。它解决的是并发资源互斥的问题,不是安全问题。
我见过很多团队拿Redis做分布式锁,为了防止"误删他人锁"加了唯一标识,为了防止"持有锁的线程挂了没释放"给锁加了过期时间。这套机制已经比较成熟了,但有一个容易翻车的地方:主从模式下,如果主库宕机,从库晋升为主库后,锁的信息可能还没同步过去,导致两个客户端同时拿到锁。
正规的解法是RedLock算法,或者干脆用ZooKeeper、etcd这类强一致性组件来做分布式锁。这已经超出Redis漏洞的范畴了,但既然热词里出现了分布式锁,我还是想提醒一句:Redis适合做缓存,做分布式锁要慎重,尤其在主从和哨兵场景下,它的安全边界并没有你想象的那么清晰。
5.3 可视化工具与运维习惯:最后一个环节的隐患
最后聊一个容易被忽略的环节——可视化客户端。Redis Desktop Manager、AnotherRedisDesktopManager这类工具确实好用,但如果你在办公电脑上装一个直接连生产Redis,还开启了"保存密码"功能,那风险就不只是Redis本身了,而是整个办公网的安全边界。
我见过不止一次:开发同学拿RDM连着生产Redis,顺手把连接配置导出到了本地文件,后来这台笔记本中了木马,Redis的用户名密码全部被翻出来,攻击者拿着这些凭据直接进了生产库。所以运维习惯也是安全的一部分——生产环境的凭据要集中管理,不要散落在个人终端上。
写在最后的个人经验
回到开头那个问题:怎么判断自己的Redis中没中招?其实没有一个万能答案,因为攻击者的手法一直在变。但有一点是确定的:如果你连"我的Redis绑定了哪些IP、谁有权限访问、日志在哪里看、有没有告警"这几个问题都答不上来,那你大概率还处于裸奔状态。
我个人的习惯是每季度做一次Redis安全自检:敲一遍INFO看详情,看一次MODULE LIST,查一遍redis.log里的危险命令记录,顺手改一次高权限密码。这套动作看着简单,但确实帮我挡掉了不少风险。最后再分享一个小技巧:新装Redis之后,先把rename-command CONFIG ""和rename-command SLAVEOF ""配上,业务需要再放开,不需要就让它一直禁着——大多数业务根本没机会用到这些命令,但它们往往是攻击者最爱用的入口。