zoukankan      html  css  js  c++  java
  • zookeeper的未授权访问漏洞解决

    zookeeper的基本情况

    zookeeper是分布式协同管理工具,常用来管理系统配置信息,提供分布式协同服务。zookeeper官网下载软件包,bin目录下有客户端脚本和服务端脚本。另外还有个工具对理解和使用zookeeper服务非常有用,即zk-ui,该工具是zk服务端的可视化工具,可在web界面对服务端进行操作。

    zookeeper以树状结构保存数据,我们完全可以对比linux文件系统理解zookeeper的文件系统。不同点在于linux下的每个目录名对应一个znode。
    zk-file-system.JPG
    znode是zk的基本单元,可以存在数据信息、版本信息等等。如图,/是zookeeper的根节点,A、B、C和D均为znode。

    zookeeper存在的问题

    我们在使用zookeeper提供的服务的时候会发现,只要知道zk服务端的IP和Port,任务用户或者客户端根本不需要任何的认证就可以连上zk的服务端,并且可以对znode进行增删等操作。这样数据是非常不安全的,极易被攻击和篡改。

    zookeeper解决这个问题的手段是ACL(access control list)机制,即访问控制列表。

    zookeeper的ACL机制

    zookeeper通过ACL机制控制znode节点的访问权限。

    首先介绍下znode的5种操作权限:
    CREATE、READ、WRITE、DELETE、ADMIN 也就是 增、删、改、查、管理权限,这5种权限简写为crwda(即:每个单词的首字符缩写)
    注:这5种权限中,delete是指对子节点的删除权限,其它4种权限指对自身节点的操作权限

    身份的认证有4种方式:
    world:默认方式,相当于全世界都能访问
    auth:代表已经认证通过的用户(cli中可以通过addauth digest user:pwd 来添加当前上下文中的授权用户)
    digest:即用户名:密码这种方式认证,这也是业务系统中最常用的
    ip:使用Ip地址认证

    本文以digest认证方式展开说明。我们在zk的客户端可以进行节点权限的查看和设置。

    [zk: localhost:2181(CONNECTED) 3] create /test data
    Created /test
    [zk: localhost:2181(CONNECTED) 2] getAcl /test
    'world,'anyone
    : cdrwa
    [zk: localhost:2181(CONNECTED) 3] addauth digest user:password
    [zk: localhost:2181(CONNECTED) 4] setAcl /test auth:user:password:cdrwa
    [zk: localhost:2181(CONNECTED) 5] getAcl /test
    'digest,'user:V28q/NynI4JI3Rk54h0r8O5kMug=
    : cdrwa    
    

    从上述操作可以看出,zk新创建的znode默认访问方式为world。我们通过addauth和setAcl给/test节点设置访问权限为digest,操作权限为cdrwa,用户名为user,密码为password。

    当然,我们使用getAcl是无法获取可访问用户test的明文密码的(要是可以获取明文密码,不又是个漏洞嘛~~)。

    另启zk客户端,执行ls /test,发现当前用户已经无法访问/test节点,提示信息为“Authentication is not valid”。解决方法就是addauth添加认证用户了,并且必须使用用户名和密码明文进行认证。

    [zk: localhost:2181(CONNECTED) 0] ls /test
    Authentication is not valid : /test
    [zk: localhost:2181(CONNECTED) 4] addauth digest user:password
    [zk: localhost:2181(CONNECTED) 5] ls /test
    [] 
    [zk: localhost:2181(CONNECTED) 6] create /test/leaf data
    Created /test/leaf
    [zk: localhost:2181(CONNECTED) 7] getAcl /test/leaf
    'world,'anyone
    : cdrwa
    

    addauth添加digest认证用户user后,即可正常访问/test节点了。

    另外,还有一点需要注意,znode的ACL是相互独立的。也就是说,任意不同节点可以用不同的acl列表,互不影响,并且ACL是不可被继承的。
    我们在/test下创建leaf节点,可发现,leaf节点的认证方式为world,即任何用户都有访问权限。

    使用Java解决zk的未授权访问漏洞

    还是以digest为例:

    //给密码加密
    public String getDigestUserPswd(String idPassword) throws NoSuchAlgorithmException {
    return DigestAuthenticationProvider.generateDigest(idPassword);
    }
    //获取ACL列表,这里只设置一个可访问用户,用户名为user,密码为pswd。如果你需要多个,继续add即可。
    public List<ACL> getAclList() {
    String idPassword = "user:pswd";
    if (idPassword == null) {
    logger.warn("no digest config,so use world scheme");
    return ZooDefs.Ids.OPEN_ACL_UNSAFE;
    }
    List<ACL> aclList = new ArrayList<>();
    try {
    Id zkUser = new Id("digest", getDigestUserPswd(idPassword));
    ACL acl = new ACL(ZooDefs.Perms.ALL, zkUser);
    aclList.add(acl);
    } catch (NoSuchAlgorithmException e) {
    logger.error(e);
    }
    return aclList;
    }
    //给znode设置权限,只有aclList的用户可以访问
    public void addDigestScheme(){
    zk.setACL(znode, aclList, -1);
    }
    //创建znode的时候设置ACL
    zk.create(znode,data,aclList,...)
    //如何访问加密的znode
    public void client(){
    ZooKeeper zk = new ZooKeeper(xxx)
    zk.addAuthInfo("digest","user:pswd".getBytes())
    //然后zk就可以访问加密znode了
    }
    
    

    上面的代码仅说明了核心步骤。
    我在这里遇到个大坑,就是idpasswod为空的情况,之前直接给返回空了,feature正常启动,但是服务没有成功的发布出去。重要的是构建环境把我在配置文件配置的user信息给删掉了(我不知道)才开始跑的,更坑的是它运行完后直接清除日志了,哪里错了都看不到。
    最后哼哧哼哧的啃代码,终于定位到位置。
    血泪教训:空指针情况需要正确处理,别TMD的随便返回空,运行没问题不代表功能没问题。

    到这里,我们在create节点的时候可以为所有的znode设置访问权限,理论上可以保护我们的数据安全了。

    漏洞扫描验证

    上面我们在创建znode的时候进行了加密,这样总可以通过漏洞扫描了吧。
    重点来了。

    但是如果你使用漏洞扫描工具扫描的话,还是有未授权访问漏洞的,为啥呢?
    不知道你有没有注意,zk服务端启动后,默认会启动这几个具有world和cdrwa权限的znode,“/” "/zookeeper" "/zookeeper/config"和"/zookeeper/quota"(根据zookeeper的版本不同可能存在不同,并且这几个节点虽然具有world和cdrwa权限,但是是无法删除的,不知道为什么,好在我们可以给它设置ACL列表。另外,官网对着几个节点也没有特别说明,估计和zk本身的一些配置相关吧,不删除最好)。就是这几个znode,会导致你的产品无法通过安全工具的漏洞扫描,你说坑不坑,解决办法也是很简单的,用我们前面说过的zk.setACL为这几个节点设置权限就OK了,千万别忘记根节点"/"了。

    好了,到这里,才是真正的解决了这个未授权访问漏洞问题了。

  • 相关阅读:
    挑战程序设计竞赛第二章、贪心部分
    Life is Strange:《奇异人生》
    算法竞赛进阶指南第二章--题解
    算法竞赛进阶指南第一章题解
    2018 IEEE极限编程大赛 题解
    爬格子呀9.17(图论)
    大数模板(加减乘除幂次开方)
    地理位置(Geolocation)API 简介
    javascript闭包的理解
    H5本地离线存储
  • 原文地址:https://www.cnblogs.com/ilovena/p/9484522.html
Copyright © 2011-2022 走看看