前言
公司在做安全漏洞掃描。發現CDH Zookeeper存在未授權訪問入侵問題。
1.zookeeper的基本情況
zookeeper是分布式協同管理工具,常用來管理系統配置信息,提供分布式協同服務。zookeeper官網下載軟件包,bin目錄下有客戶端腳本和服務端腳本。另外還有個工具對理解和使用zookeeper服務非常有用,即zk-ui,該工具是zk服務端的可視化工具,可在web界面對服務端進行操作。
zookeeper以樹狀結構保存數據,我們完全可以對比linux文件系統理解zookeeper的文件系統。不同點在於linux下的每個目錄名對應一個znode。
znode是zk的基本單元,可以存在數據信息、版本信息等等。如圖,/是zookeeper的根節點,A、B、C和D均為znode。
2.zookeeper存在的問題
我們在使用zookeeper提供的服務的時候會發現,只要知道zk服務端的IP和Port,任務用戶或者客戶端根本不需要任何的認證就可以連上zk的服務端,並且可以對znode進行增刪等操作。這樣數據是非常不安全的,極易被攻擊和篡改。
zookeeper解決這個問題的手段是ACL(access control list)機制,即訪問控制列表。
3.zookeeper的ACL機制
zookeeper通過ACL機制控制znode節點的訪問權限。
傳統的文件系統中,ACL分為兩個維度,一個是屬組,一個是權限,子目錄/文件默認繼承父目錄的ACL。而在Zookeeper中,node的ACL是沒有繼承關系的,是獨立控制的。Zookeeper的ACL,可以從三個維度來理解:一是scheme; 二是user; 三是permission,通常表示為
'scheme,'id
:permissions
下面從這三個方面分別來介紹:
scheme: scheme對應於采用哪種方案來進行權限管理,zookeeper實現了一個pluggable的ACL方案,可以通過擴展scheme,來擴展ACL的機制。zookeeper-3.4.4缺省支持下面幾種scheme:
- world: 它下面只有一個id, 叫anyone, world:anyone代表任何人,zookeeper中對所有人有權限的結點就是屬於world:anyone的
- auth: 它不需要id, 只要是通過authentication的user都有權限(zookeeper支持通過kerberos來進行authencation, 也支持username/password形式的authentication)
- digest: 它對應的id為username:BASE64(SHA1(password)),它需要先通過username:password形式的authentication
- ip: 它對應的id為客戶機的IP地址,設置的時候可以設置一個ip段,比如ip:192.168.1.0/16, 表示匹配前16個bit的IP段
- super: 在這種scheme情況下,對應的id擁有超級權限,可以做任何事情(cdrwa)
permission: zookeeper目前支持下面一些權限:
- CREATE(c): 創建權限,可以在在當前node下創建child node
- DELETE(d): 刪除權限,可以刪除當前的node
- READ(r): 讀權限,可以獲取當前node的數據,可以list當前node所有的child nodes
- WRITE(w): 寫權限,可以向當前node寫數據
- ADMIN(a): 管理權限,可以設置當前node的permission
3.1IP白名單模式授權
進入到zk目錄
cd /opt/cloudera/parcels/CDH/lib/zookeeper/bin
進入zk客戶端
./zkCli.sh -server xxx.xxx.xxx.xxx:2181
對需要進行白名單設置的路徑進行設置,此處設置的路徑沒有繼承關系,即設置了/test的白名單,但是/test/test2依然沒有設置為白名單。
setAcl /test ip:127.0.0.1:cdrwa
多個ip之間用逗號隔開,如:
setAcl /test ip:127.0.0.1:cdrwa,ip:192.168.10.3:cdrwa
通過此IP白名單設置之后,即只允許設定過的IP服務器才能進行訪問,其他機器無法訪問。
3.2auth模式授權
3.2.1添加用戶
addauth digest ramboo:ramboo
可以添加多個用戶,如
addauth digest ramboo1:ramboo1
addauth digest ramboo2:ramboo2
addauth digest ramboo3:ramboo3
3.2.2設置Acl權限
此處假如對/auth路徑進行設置,則
setAcl /auth auth:ramboo1:ramboo1:cdrwa
注:此處雖然設置了ramboo1用戶的權限,但是zk會默認添加所有存在的用戶。此處需要注意。
3.2.3查看Acl權限
getAcl /auth
結果如下所示:
'digest,'ramboo1:JXpHVJcEMUsIf5MM6u7TlOp3pqo= : cdrwa 'digest,'ramboo2:lTTHGKOT6A3iEwj/SV5meGTXbAM= : cdrwa 'digest,'ramboo3:b8+HkvFoPszTILQTMB1YFQ+Yvus= : cdrwa
注:如果退出了客戶端,再進入的時候,需要重新添加用戶,才可訪問,即授權。
3.3digest模式授權
此模式,和auth模式的區別在於:
1、digest設置Acl的時候,可以不用先添加用戶,而auth設置Acl的時候,是需要提前設置用戶的,否則報錯。 2、digest設置的密碼要用密文,auth設置的密碼是明文。 3、auth設置的,只需設置一個用戶,就可以把所有用戶設置進去,而digest不行,只能對本次設置的用戶有效。也就是auth模式忽略id。
3.3.1生成密文密碼
在Linux下執行如下命令
echo -n xing:xing | openssl dgst -binary -sha1 | openssl base64
結果為:
kgk4DGva6vqOBYMGbMsXBZuFCXE=
3.3.2設置Acl權限
此處假如對/digest路徑進行設置,則
setAcl /digest digest:xing:kgk4DGva6vqOBYMGbMsXBZuFCXE=:cdrwa
#添加多個用戶,則用逗號隔開
注:此處的密文密碼不要隨意更改,否則不知道對應的明文是多少,后續就沒辦法訪問對應節點,切記!
注:此處的密文密碼不要隨意更改,否則不知道對應的明文是多少,后續就沒辦法訪問對應節點,切記!
注:此處的密文密碼不要隨意更改,否則不知道對應的明文是多少,后續就沒辦法訪問對應節點,切記!
3.3.3查看Acl權限
此時如果沒有添加xing這個用戶,需要先添加,才可查看。添加命令如下:
addauth digest xing:xing
添加后,可查看:
getAcl /digest
結果為:
'digest,'xing:kgk4DGva6vqOBYMGbMsXBZuFCXE=
: cdrwa
4.忘記密碼修復方式
如果對上述設置授權后,忘記密碼了,怎么辦?方法如下:
- 進入配置文件zoo.cfg,修改配置,設置跳過Acl驗證,配置如下:
skipACL=yes
- 重啟zookeeper
- 啟動后,可按照第一節所述的方式,重新進行Acl設置即可
5.利用zookeeper api進行zk實例的初始化和權限添加
代碼示例
//給密碼加密 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 public void client() { ZooKeeper zk = new ZooKeeper(xxx); zk.addAuthInfo("digest", "user:pswd".getBytes()); }
上面的代碼僅說明了核心步驟。
6.漏洞掃描驗證
上面我們在創建znode的時候進行了加密,這樣總可以通過漏洞掃描了吧。
重點來了。
但是如果你使用漏洞掃描工具掃描的話,還是有未授權訪問漏洞的,為啥呢?
不知道你有沒有注意,zk服務端啟動后,默認會啟動這幾個具有world和cdrwa權限的znode,“/” "/zookeeper" "/zookeeper/config"和"/zookeeper/quota"(根據zookeeper的版本不同可能存在不同,並且這幾個節點雖然具有world和cdrwa權限,但是是無法刪除的,不知道為什么,好在我們可以給它設置ACL列表。另外,官網對着幾個節點也沒有特別說明,估計和zk本身的一些配置相關吧,不刪除最好)。就是這幾個znode,會導致你的產品無法通過安全工具的漏洞掃描,你說坑不坑,解決辦法也是很簡單的,用我們前面說過的zk.setACL為這幾個節點設置權限就OK了,千萬別忘記根節點"/"了。
好了,到這里,才是真正的解決了這個未授權訪問漏洞問題了。
建議:如果zookeeper安裝在阿里雲服務器上的話,可以忽略此漏洞,通過安全組進行權限訪問。