资讯动态

Redis未授权访问漏洞详解:从原理分析到CVE-2024-46981修复加固

发布时间:2026/10/17 7:50:29 来源:尧图企业网站定制
前段时间我接手一个生产环境的安全巡检扫描工具一拉内网里十几个Redis实例直接裸奔在6379端口上redis-cli连进去就能执行info整个缓存数据一览无余。更麻烦的是这类未授权访问一旦被外部盯上攻击者不光能删库还能往服务器上写定时任务、写SSH公钥拖垮整个业务。这篇文章把Redis未授权访问漏洞从头到尾拆一遍漏洞为什么存在、攻击者能做什么、修复加固具体怎么做标题里提到的CVE-2024-46981我也会单独讲一套落地的版本升级方案。无论你是刚接触Redis的开发者还是在维护老系统的运维都能从中找到可以直接抄的作业。1. 漏洞原理拆解为什么Redis会裸奔在网络上1.1 Redis的默认设计哲学埋下的隐患Redis从设计之初就定位在可信内网环境里使用早期版本默认只监听本机回环地址127.0.0.1这种配置下外部网络根本摸不到6379端口。问题出在后来的多次迭代里很多人安装Redis时图省事直接拷贝一份网上找的简化配置或者用包管理器装完也不改默认项导致服务监听在0.0.0.0上等于对全网开放。更核心的问题在于Redis本身没有强制认证机制。Redis 6.0之前只有一条requirepass设置密码默认是空的。也就是说只要你的实例监听地址不是内网专用任何能触达6379端口的人都可以直接发命令。这就是未授权访问漏洞最根本的成因一个监听在公网或非隔离网段、又没有开启身份校验的高权限服务。protected-mode这个保护模式是Redis 3.2之后加的一层兜底机制在没设置密码、没配置bind、也没配置rename命令的时候它会让Redis拒绝来自非回环地址的访问。很多老实例跑在旧版本上根本没有这层保护有些新环境里运维为了图省事配置了绑定*保护模式也会被自动绕过。所以不要以为版本新就安全配置组合不合理漏洞依然存在。1.2 未授权访问的完整攻击链路攻击者找到开放端口后黑白行为通常遵循一套固定流程第一步是探测可用性。攻击者用客户端直接连上6379发送PING命令如果返回PONG说明端口背后是一个可以交互的Redis服务而且当前连接没受任何认证拦截。第二步是信息收集。执行INFO命令拿到当前实例的版本号、运行模式、配置项、已连接客户端数量、内存和CPU占用。这些信息对攻击者来说价值极高因为版本号直接决定了下一步能用哪些已知漏洞已缓存的数据规模则决定了勒索或窃取的优先级。第三步是数据嗅探与篡改。通过KEYS *枚举所有key再配合GET逐个读取敏感的缓存数据、会话令牌、业务配置全部暴露。有些场景攻击者不会直接删库而是挑几个关键key改掉业务逻辑这种温水煮青蛙的方式更难被察觉。第四步是获取服务器权限。Redis支持CONFIG SET dir和CONFIG SET dbfilename指令攻击者可以改变数据库文件的写入路径和文件名把恶意内容写进定时任务文件、SSH授权文件或者Web目录里配合后续触发机制直接拿到服务器Shell。这一整套下来Redis就从一个数据组件变成了攻击者横向移动的跳板。2. 危害盘点比数据被删更严重的事2.1 数据泄露和勒索是最直接的两把刀很多人一听到Redis未授权访问第一反应就是最多被清空数据。实际上数据被flushall只是经济损失最轻的一种。缓存里经常存着用户会话、订单状态、验证码、权限标记这些数据被拖走之后攻击者可以拿着它继续攻击业务系统撞库、越权、伪造登录态每一步都能把损失放大。还有一类更隐蔽的危害攻击者把maxmemory策略改成noeviction再写入大量垃圾key把可用内存耗尽触发系统的内存碎片整理和换页让Redis的响应时间从毫秒级变成秒级直接影响线上接口的可用性。这种破坏不仅查不出明显痕迹还会让运维误判成业务容量问题排查方向整个跑偏。生产环境里还有一种常见场景Redis被用来做分布式锁或者消息队列。攻击者篡改某个锁key让其他服务获取不到锁导致任务调度卡死、数据重复写入、上下游链路脏数据堆积。这类问题不像删库那么显眼但修复成本反而更高。2.2 从Redis到服务器Shell的远程控制链条Redis未授权访问真正可怕的点在于它能从数据面穿透到系统面。最经典的一条路径是往/var/spool/cron/下写定时任务文件。攻击者先构造一段反弹命令比如通过CONFIG SET dir把数据库目录切到定时任务目录再设置dbfilename为当前用户名对应的任务文件然后用SET写入任务内容最后触发SAVE把内容落盘。等到系统下一次执行定时任务时恶意命令就会在服务器上跑起来。另一种常见手法是对着SSH授权文件动手。如果Redis进程的运行用户对/root/.ssh/或目标用户的~/.ssh/有写权限攻击者可以把攻击机的公钥写入authorized_keys之后直接用私钥免密登录服务器。整个过程不需要任何系统漏洞依赖的仅仅是Redis的高权限写文件能力。生产环境里还出现过利用Redis未授权访问修改主从复制配置、搭建恶意主节点传播payload的案例。攻击者先让自己的服务器扮演主节点诱导目标Redis通过SLAVEOF命令同步恶意数据配合模块加载机制把恶意代码以共享库形式加载进Redis进程实现远程代码执行。这也是这类漏洞在攻防演练中被高频利用的原因——入口单一危害却可以蔓延到整台主机和同网段的其他机器。3. 修复方案落地四步搞定基础加固3.1 绑定监听地址让Redis不对外网开口修复Redis未授权访问第一步不是加密码而是先用bind把监听范围收窄。绝大多数业务场景下Redis只需要被本机或内网特定网段的有限几个应用服务器访问完全没有必要对所有网卡开放。打开Redis配置文件找到bind这一行# /etc/redis/redis.conf # 原来可能长这样 bind 0.0.0.0 # 改成本机和内网地址 bind 127.0.0.1 192.168.10.15这里有个细节要注意如果配置了多个Redis实例做集群或主从bind里面必须包含主从之间实际通信用的网卡IP不能只保留127.0.0.1否则跨节点复制会直接失败。改完之后用redis-cli CONFIG REWRITE或者重启服务让配置生效然后用以下命令确认监听地址netstat -tlnp | grep 6379 ss -tlnp | grep redis正常情况下应该只能看到127.0.0.1和指定内网IP在监听6379而不是*:6379。3.2 开启密码认证与ACL访问控制绑定IP只是收窄了暴露面内网里同样不安全所以必须开启认证。基础做法是在配置文件里设置一个强密码requirepass 你的强密码强密码建议用至少16位的随机字符串包含大小写字母、数字和特殊字符不要用单词拼接更不要直接用123456这类明文。生成方式可以直接用openssl rand -base64 24。重启服务后客户端连接时需要通过认证redis-cli -a 你的强密码不过从Redis 6.0开始官方更推荐用ACL访问控制列表做细粒度权限管理。ACL可以给不同用户分配不同的命令权限和key前缀权限比全局一个requirepass精细得多。举个例子# 在redis-cli里执行 ACL SETUSER appuser on appStrongPassword ~app:* get set expire ttl del ACL SETUSER backupuser on backupStrongPassword ~* info save bgsave上面第一条创建了一个叫appuser的账号只能操作app:前缀的key允许的命令只有get、set、expire、ttl、del第二条给了备份账号读和备份的权限。如果某个账号只需要读数据就只给get mget hget这类查询命令不给任何写命令。3.3 保护模式与危险命令的收敛protected-mode设成yes并配合正确的bind配置可以在未设置密码前就拦截一部分外部访问。它的行为逻辑是如果没显式设置密码、并且没有显式绑定非回环地址实例会拒绝来自非本机地址的连接。但要注意一旦你配置了bind指定内网IP保护模式的拦截条件就已经被破坏了所以它只能算一道心理安慰层绝不能当主要防御。危险命令的收敛也很关键。KEYS、FLUSHALL、FLUSHDB、CONFIG、EVAL、SCRIPT这几个命令在常规业务里基本用不上但攻击者一旦拿到连接权限就会优先尝试它们。Redis本身提供命令重命名和禁用机制在配置文件里加上rename-command FLUSHALL rename-command FLUSHDB rename-command CONFIG rename-command KEYS rename-command SHUTDOWN 把命令重命名为空字符串等于彻底禁用。如果业务里确实需要KEYS做查询建议改成SCAN同时限制只能扫特定前缀。还要留意DEBUG命令它在一些版本里可以直接set内部参数、触发崩溃属于高危命令同样建议禁用。3.4 网络层兜底防火墙与安全组双保险即便Redis配置全部拉满我还是坚持在网络层再补一道闸。道理很简单配置是软件层的逻辑防火墙是系统层的硬隔离两者互不替代。一旦哪天多实例配置写错、或者升级后配置回滚防火墙还能挡住来自错误方向的流量。以Linux自带的防火墙为例放行特定来源IP的6379端口# firewalld firewall-cmd --permanent --add-rich-rulerule familyipv4 source address192.168.10.0/24 port protocoltcp port6379 accept firewall-cmd --reload # iptables iptables -A INPUT -p tcp --dport 6379 -s 192.168.10.0/24 -j ACCEPT iptables -A INPUT -p tcp --dport 6379 -j DROP云服务器还要检查安全组规则。安全组是网络层最外层的闸门很多线下环境Redis裸奔就是因为安全组入方向全放开了。操作时记住一个原则Redis端口只放给真正需要访问它的应用服务器IP段数据库服务和中间件服务不要混用同一个安全组规则避免牵连过广。4. CVE-2024-46981专项修复版本升级与验证4.1 这个CVE背后的漏洞类型和影响逻辑标题里单独提到CVE-2024-46981因为它不是普通配置层面的问题而是已经被官方收录的代码级缺陷。按照安全通告里的描述这类问题的共通点在于某些特定配置组合下访问控制校验可以被绕过甚至在已开启认证的实例上攻击者仍有机会通过异常命令构造触发未预期的状态变更。和纯配置失误不同这种缺陷无法靠改配置文件规避必须通过升级版本或者应用官方补丁来修复。从影响范围看这个CVE波及多个早期版本分支。如果你的线上实例还停留在老旧版本又恰好对外监听了端口风险等级完全是公开可利用状态。所以看到这里第一件事就是登录Redis实例确认版本号redis-cli info server | grep redis_version或者直接用redis-server --version确认版本之后对照官方安全通告看是否落在受影响区间。这里要特别提醒一句不要只盯着大版本号比如看到6.x就觉得没问题很多补丁都是小版本里合入的6.2.0和6.2.15的安全状态完全是两码事。4.2 升级修复的完整操作过程升级流程我会分准备、停服、更新、启动四步走全程以最小影响为原则。准备阶段先把配置和持久化文件备份好cp /etc/redis/redis.conf /etc/redis/redis.conf.bak.$(date %Y%m%d) redis-cli -a 你的密码 --rdb /data/backup/redis_full_backup.rdb然后确认当前启动方式。如果是systemd托管直接查服务状态systemctl status redis如果是纯手动启动找到启动命令里的配置文件路径防止升级后用了错误配置。停服阶段要注意业务窗口。Redis作为缓存被强依赖时停服会直接放大流量打到数据库上所以升级前最好确认业务低峰期。停服命令systemctl stop redis更新阶段用包管理器升级到最新修复版本# CentOS/RHEL等使用yum的方式 yum update redis -y # Debian/Ubuntu等使用apt的方式 apt update apt install --only-upgrade redis-server -y如果线上环境比较特殊存在多个Redis实例共存的场景建议用二进制替换的方式升级解开新版本压缩包到指定目录然后通过软链接或者直接替换可执行文件保证多个实例可以同时平滑切换。启动阶段先小范围验证再全量拉起systemctl start redis systemctl status redis redis-cli -a 你的密码 info server | grep redis_version确认版本号已经落在修复版本之后才算真正告一段落。4.3 升级后的功能回归验证升级后不能只看版本号变了就宣告修复完成功能回归验证必须跟上。我这里有一套常用检查清单先验证基础读写。用SET写入一个测试key再GET读回来确认数据通道正常。接着验证持久化执行一次SAVE或BGSAVE确认rdb文件正常生成。再看业务侧是否能正常连接。如果应用用了旧版客户端库个别命令在协议细节上可能和新版本有兼容差异需要重点核对连接池日志出现超时或命令拒绝时优先看服务端日志。最后检查监控指标。升级后短期Redis的used_memory、connected_clients、rejected_connections都会有波动如果connected_clients掉到接近0且没回升多半是应用连接配置里还有老密码或者认证方式没跟上。注意如果版本跨度很大比如直接从3.x跳到7.x配置文件里有些参数会失效。升级前用redis-server /path/to/redis.conf先做一次语法检查能拦截大部分配置兼容问题。5. 漏洞检测与修复验证如何确认自己真的安全了5.1 三分钟自查是否存在未授权访问快速自查最简单的方法是模拟攻击者视角从一个非本机的位置尝试连接Redis。假设Redis服务器IP是192.168.10.15在另一台机器上执行redis-cli -h 192.168.10.15 -p 6379 PING如果返回PONG说明当前存在未授权访问风险。如果返回NOAUTH Authentication required说明密码认证已经生效。如果连接直接超时或被拒绝说明网络层隔离已经挡住了。这种测试一定要从外部网络发起不能只在Redis本机上测。本机上测不管配置多烂回环地址通常都能连上测不出真实暴露情况。5.2 配置基线核查要点安全配置基线往往比扫漏洞更能反映真实状态我总结了一份快速核查清单检查项目包括bind是否只包含必要的内网IPprotected-mode是否为yesrequirepass或ACL用户是否已经配置rename-command是否覆盖了高危命令maxmemory策略是否限定了内存使用上限appendonly落盘目录是否在合理路径服务的启动用户是否为非root专用账号。逐项打分之后只要有一个关键项不达标就应该纳入修复清单。尤其注意服务启动用户如果Redis进程是以root身份运行的一旦未授权访问被利用写SSH公钥、写定时任务这类攻击会变得畅通无阻。生产环境建议单独建一个redis系统用户用useradd -M -s /sbin/nologin redis创建然后在配置文件的启动参数里指定运行用户。5.3 自动化巡检思路人工核查容易漏我习惯再加一个自动化巡检脚本兜底。脚本思路很简单对内网所有6379端口做连接发PING命令看是否被拒绝同时抓取INFO返回里的版本号、开启保护模式状态、监听地址三项信息生成一份报告。下面是一个简化版Python检测脚本可以放在运维机上定期执行import socket import json targets [192.168.10.15, 192.168.10.16, 192.168.20.11] def check_redis(host, port6379, timeout3): try: s socket.create_connection((host, port), timeouttimeout) s.sendall(bPING\r\n) resp s.recv(1024).decode(errorsignore) if resp.startswith(PONG): return {host: host, risk: unauth-access, ping_resp: resp.strip()} elif NOAUTH in resp.upper(): return {host: host, risk: auth-enabled, ping_resp: resp.strip()} else: return {host: host, risk: unknown, ping_resp: resp.strip()} except Exception as e: return {host: host, risk: unreachable, error: str(e)} results [] for h in targets: results.append(check_redis(h)) for r in results: print(json.dumps(r, ensure_asciiFalse))这个脚本不依赖扫描器一键运行后立刻能看到哪台机器还没有开启认证。跑完之后把结果接入监控平台的告警通道新发现的未授权访问实例就能第一时间被发现。6. 常见问题与踩坑实录6.1 改了配置之后Redis反而连不上了这是加固以后出现频率最高的一个问题。改完bind或者开启密码认证后应用端连不上Redis第一反应通常是配置改错了其实大多数是应用连接参数没同步更新。排查路径我建议按顺序来先看Redis进程是否真的监听在新的地址和端口上。执行ss -tlnp | grep 6379确认监听地址是否是配置里的那个IP。再看防火墙规则是否放行了新地址范围特别是从本地IP改成内网IP后之前的防火墙规则可能只放行了本地网卡的流量。最后检查应用配置里的连接地址和密码确认它们与Redis新配置严格一致。还有一种隐蔽情况多个配置文件并存。Redis启动时可以通过命令行参数指定配置文件有些初始化脚本用的是/system/other路径下的副本你改了/etc/redis/redis.conf但服务启动时加载的却是另一个文件。排查时一定要在启动命令里确认实际加载路径。6.2 密码认证开启后集群和哨兵模式全崩了单机环境下开启ACL简单但集群模式里会多出很多坑。Redis Cluster用cluster-cipher和cluster-auth做节点间认证开启ACL后如果没同步配置节点间通信的账号节点之间会反复握手失败集群状态直接变成fail。同样哨兵模式里Redis Sentinel连接主节点和数据节点也需要认证信息。很多人在redis.conf里给数据节点配了requirepass却忘了在哨兵配置里加sentinel auth-pass结果就是哨兵不断报错-NOAUTH主从切换完全失效。建议在开启认证前先梳理整个架构里所有节点和客户端的连接链条列一张谁在连谁的表格把认证信息在配置阶段全量化避免启动后分头排查。6.3 加密码之后高并发性能到底掉多少这是很多团队拒绝加密码的理由担心认证开销影响性能。实测下来Redis处理AUTH命令的开销微乎其微因为认证只发生在连接建立的瞬间并不会对后续每个命令都做额外加密计算。在高并发场景下影响最大的是连接频繁建立与认证的开销相比TCP建连本身的成本占大头。真正需要关注的是requirepass和ACL混用时的配置顺序。有些团队先设置了requirepass又用ACL创建了账号结果客户端连接时优先尝试ACL账号密码不匹配时会额外增加一次握手失败开销。正确做法是线上环境统一走ACL用户体系requirepass作为兼容过渡或彻底关闭。6.4 升级后内存和持久化异常版本升级后最容易被忽略的是持久化文件格式兼容性。Redis各版本的RDB格式虽然大体兼容但跨大版本升级后老版本生成的RDB文件在极端情况下可能加载异常。升级前用老版本执行一次DEBUG RELOAD或者SHUTDOWN SAVE确保内存数据先落盘再用新版本启动时做一次主动加载测试。如果升级后发现内存上涨明显优先检查maxmemory策略是否被重置成默认值。有些发行版的升级包会把配置里的maxmemory注释掉导致实例不再受内存上限约束一旦业务流量增长Redis就可能把宿主机内存吃光。升级后第一件事就是复核所有非默认配置项别指望配置文件原封不动。7. 最后再分享两个实践中练出来的小经验第一修复未授权访问这件事优先级排序应当是先收网、再上锁、后升级。先通过bind和防火墙把端口暴露面收小再上密码和ACL把认证补上最后处理CVE这类需要版本升级的问题。顺序错了容易在升级窗口期扩大暴露时间风险不减反增。第二所有加固操作都要留可回退的备份和记录。我在实际处理中每次改动配置文件都会保留带时间戳的备份并把变更清单写到维护记录里。Redis本身在安全这块的迭代越来越快但再新的版本也架不住错误配置安全是一个持续动作不是一次升级就能一劳永逸的事。修好一个实例后建议顺手把同网段的同类服务都扫一遍很多环境往往不止一台机器中招漏掉一台就等于没修。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑