ZooKeeper 未授权访问漏洞:你做的 ACL 加固可能只是“假动作”
在日常安全加固中经常会收到基础架构或安全部门的反馈ZooKeeper 存在未授权访问漏洞。很多同学拿到需求后的第一反应是“加个 ACL 就好了”于是动手操作一轮添加超级用户、给某个节点设置 IP 白名单、然后觉得超级用户碍事把它删掉顺便禁掉四字命令。这一套“组合拳”打下来是不是就算修复完成了答案是远没有。本文将以一个实际的操作过程为例拆解其中的误区并给出真正有效的修复方案。一、常见的“加固”操作回顾假设我们接到了漏洞修复任务顺手完成了以下步骤添加超级用户在zoo.cfg中配置superDigest让super用户获得最高权限-Dzookeeper.DigestAuthenticationProvider.superDigestsuper:cY9eK20soteVC3fQ83SXDvwlP0重启节点后可以用addauth digest super:cloudera登录。为特定 znode 设置 IP 白名单 ACLcreate /znode1 setAcl /znode1 ip:192.168.0.74,192.168.0.75:cdrwa意思是只有192.168.0.74和192.168.0.75能读写/znode1。验证权限用.75访问/znode1成功用.76访问/znode1被拒绝Authentication is not valid。感觉“ACL 生效了”。删除超级用户配置去掉superDigest行重启节点让超级用户失效。禁用危险的四字命令限制白名单4lw.commands.whitelistconf,cons,crst,dirs,dump,gtmk,ruok,stmk,srst,srvr,stat,wchs,mntr,isro看上去有认证、有 ACL、有指令限制但为什么漏洞报告依然存在二、问题究竟出在哪里1. ACL 没有递归性根节点及其他节点仍然“裸奔”ZooKeeper 的 ACL 模型不是树状继承的。你对/znode1设置了ip限制但对根节点/、/zookeeper以及无数其他业务节点并没有做任何限制。这些节点的 ACL 仍然停留在默认值world:anyone:cdrwa这意味着任何一个能访问 ZooKeeper 2181 端口的客户端都可以ls /列出所有节点get /敏感数据直接读取create /evil创建非法节点delete /关键路径进行破坏。“只保护一个节点”在安全层面上等同于没保护。2. IP 白名单的认证强度不足ip模式的 ACL 完全依赖客户端来源 IP。它的缺点很明显同一网段的任何机器只要 IP 被列入白名单就拥有完整权限无法区分“谁来操作”IP 可能被伪造或者作为跳板机被攻陷后滥用缺乏账号体系无法审计、无法精准回收权限。所以用 IP ACL 来兜底未授权访问安全部门通常是不接受的他们会要求采用digest 或 SASL 认证。3. 删除了超级用户阻塞了最后的应急通道Super 用户是一种特殊的 digest 认证可以无视所有 ACL 进行操作。它的设计初衷正是防止误配 ACL 把自己完全锁在外面提供一条“超级后门”用于恢复。你在没有建立完善的全局认证机制之前就把 super 用户删掉一旦将来某个节点 ACL 配错导致所有业务账号都无法访问集群将陷入不可管理的状态。安全加固不允许这种“玉石俱焚”的做法。4. 四字命令限制是独立漏洞不能替代访问控制禁用危险的四字命令如wchc、wchp、dump等确实能阻止信息泄露和部分 DoS 攻击但这是另一个漏洞。正常的 ZooKeeper 客户端 API 根本不需要四字命令就能读写数据因此数据节点的未授权访问漏洞依然原封不动。三、真正的修复方案要彻底关闭“ZooKeeper 未授权访问漏洞”必须做到任何未经认证的客户端连ls /都执行不了。具体步骤如下1. 启用 Digest 或 SASL 认证推荐使用digest认证并让所有业务客户端在连接时主动提供账号密码。在zoo.cfg中添加authProvider.1org.apache.zookeeper.server.auth.DigestAuthenticationProvider如果你有 Kerberos 环境也可以切换到 SASL这里不展开。2. 移除根节点的 world 可访问权限选择一个或几个管理员账号用digest模式对根节点/重新设置 ACL并移除默认的world:anyone。例如# 先登录管理员账号addauth digest admin:secure_password# 设置根节点仅允许 admin 操作setAcl / auth:admin:cdrwa执行后未认证的客户端再连接进来执行ls /时会直接返回Authentication is not valid。新创建的子节点也会默认继承 ACL注意是“创建时指定 ACL 或连接会话的默认 ACL”所以还需在客户端侧设置好默认 ACL。更好的做法是创建节点时显式指定 ACL或在连接上通过setAuthInfo让所有新建节点都使用认证用户的 ACL。3. 保留超级用户作为应急入口在zoo.cfg中保留一条superDigest配置密码强度要足够并且只有核心管理员掌握。-Dzookeeper.DigestAuthenticationProvider.superDigestsuper:加密后密码不要删除它这是你最后的救命稻草。4. 结合网络访问控制与四字命令限制在防火墙或安全组层面将 ZooKeeper 的 2181 端口仅对受信 IP 段如本集群机器开放杜绝外网探测继续使用四字命令白名单只保留运维必须的少量指令。5. 验证效果使用一个未认证的客户端尝试连接zookeeper-client-serverip:2181ls/# 预期结果Authentication is not valid而正常业务客户端配置了相同的digest凭据后应该能正常读写。四、总结你认为的修复实际情况为测试节点加 ip ACL根路径、其他节点仍然world:anyone漏洞依然存在删除超级用户失去紧急管理通道加固反而降低了可用性禁用部分四字命令修复的是另一个漏洞未授权数据访问依然不受限ZooKeeper 的未授权访问漏洞核心在于默认的world:anyone:cdrwa权限。除非你显式地将根节点 ACL 改为仅认证用户可访问并以全局视角要求所有连接必须提供凭据否则漏洞就等于没有修。