Docker 映像不安全

jopen 9年前發布 | 16K 次閱讀 Docker

最近用Docker在下載一個官方鏡像容器時我看到了這一行:

ubuntu:14.04: The image you are pulling has been verified

我以為這引用了Docker 大力推廣的鏡像簽名系統,當時并沒有深究。不久之后, 在研究Docker用以加密鏡像的加密摘要系統時,有了繼續研究的機會。我發現鏡像安全相關的所有邏輯完全系統性的失效。

Docker 的報告稱一個下載的鏡像僅僅以一個簽過名的清單為驗證基礎, 并且Docker從不校驗清單上的鏡像的總和校驗碼。攻擊者可以提供任意帶有簽名清單的鏡像。這為一系列嚴重的漏洞埋下了隱患。

鏡像通過一個Docker守護進程里無安全的流處理管道從一個HTTPS服務器上下載

[decompress] -> [tarsum] -> [unpack]

這個管道高效但不安全。 非置信的輸入不應在校驗簽名之前處理。 不幸的是Docker在總和校驗碼驗證之前要處理鏡像三次。

不管 Docker的聲明 如何,鏡像總和校驗碼從來沒有實際校驗過。這只是Docker校驗鏡像總和校驗碼相關的代碼的section0 ,在呈現一個有錯誤總和校驗碼的鏡像時我甚至無法打開警告觸發器。

if img.Checksum != "" && img.Checksum != checksum {
  log.Warnf("image layer checksum mismatch: computed %q,
             expected %q", checksum, img.Checksum)
}

不安全的處理管道

解壓

Docker支持三種壓縮算法:gzip、bzip2和xz。前兩個使用的是Go的標準庫,它們是內存安全的,所以這里我想討論的利用類型是拒絕服務攻擊,比如崩潰、過多的CPU和內存使用。

第三個壓縮算法xz更加有趣。因為沒有原生的Go實現,所以Docker執行thexzbinary來解壓縮。

Thexzbinary 來自于XZ Utils項目,構建自大約20000行的C代碼。C并不是一個內存安全的語言。這意味著存在向C程序惡意輸入的可能,這樣的話Docker 鏡像XZ Utils就被開箱了,可能會執行任意代碼。
 

通過以管理員權限運行xz,Docker加劇了這個情況的發生。意味著只要在xz中存在一個漏洞,一個docker pull的調用就將導致整個系統的淪陷。

Tarsum

tarsum的使用原本是善意的但卻完全錯了。為得到一個編碼任意的tar文件的真實校驗和,Docker對tar解壓然后取特定部分的哈希,以一個特定序列卻不包含剩余部分。 

由于這個處理是為了生成校驗和,它解壓了設計用來生成tarsum碼2非可信數據。這里會有DOS和邏輯缺陷攻擊的風險,可能導致文件被注入,跳過,差異化地處理,修改,添加等等。而校驗和不會變化。

解壓

解壓包括解壓tar并將文件放置到磁盤上。這也是非常危險,在寫本文時已有三個其他的解壓階段的漏洞報告2 。

當文件還沒被校驗就解壓到磁盤上時還沒有解決措施。

libtrust

libtrust是Docker的一個包,宣稱提供“通過一個分布式的信任圖來控制認證和訪問。”但不幸的是不存在詳細說明書,但它看起來像是實現了Javascript Object Signing and Encryption說明的一部分和其他未指明的算法。

下載一個使用libtrust簽名和認證清單的鏡像,會觸發這個不安全的信息(僅僅檢查了清單,而不是真實的鏡像內容):

ubuntu:14.04: The image you are pulling has been verified

目前只有Docker,Inc發布的“官方”鏡像使用這個系統簽名,但從我最近參加的Docker Governance Advisory Board會議看,我的理解是Docker, Inc打算將來更廣泛的部署這個系統。計劃的目標是由Docker,Inc集中控制證書的認證,然后在鏡像和/或客戶端的證書上簽名。

我在Docker的代碼里找簽名鑰匙,但沒能找到。結果證明這個鑰匙并不像期望那樣嵌入到了二進制程序中。相反,Docker后臺程序在各個鏡像下載前,使用HTTPS從CDN上獲取。這個方法很糟糕,因為很多攻擊可以導致信任的鑰匙被惡意的替換。這些攻擊包括但不限于:CDN主的妥協,CDN原有托管鑰匙的妥協,以及客戶端的中間人攻擊來下載鑰匙。

修補措施

在我完成本次研究前,我報告了我發現的tarsum系統的一些問題,但目前為止我還沒發現它們被修復。我認為以下措施有助于提高Docker鏡像下載系統的安全:

丟棄tarsum,真實驗證鏡像摘要

Tarsum不應該用于安全。相反,鏡像必須被完整下載,它們的私密簽名要在進一步處理發生前進行驗證。

添加權限隔離

鏡像的處理步驟,包括解壓或展開,應該在隔離的僅有最少必要操作權限的進程(容器?)中運行。沒有像xz這樣的解壓工具在root下運行的場景。

替換libtrust

libtrust應該被The Update Framework替代,它被設計出來明顯就是為了解決軟件二進制簽名的問題。威脅模型非常好理解,也強調了許多在libtrust里面沒有考慮到的事。它有完整的說明書,也有一個Python的參考實現,我已經開始用Go實現,歡迎對其貢獻。

作為添加TUF到Docker中的一部分,應該添加一個本地key倉庫,用來將root鑰匙映射到注冊的URL上,這樣用戶就可以有自己的簽名鑰匙,而不是被Docker,Inc管理。

我想強調的是,使用非Docker,Inc托管的登記一般來說是非常差的用戶體驗。Docker,Inc看起來把第三方登記降為第二等級的狀態很滿意,而并沒有這樣做的技術原因。這對于常見的生態系統和終端用戶的安全都是一個問題。一個廣泛的、去中心化的安全模型對與第三方登記來說,既是必要的也是值得的。我建議Docker,Inc在重新設計他們的安全模型和鏡像認證系統時考慮下這個問題。

結論

Docker 用戶要意識到下載鏡像是非常不安全的。要只下載那些源沒有問題的鏡像。當前,這個問題沒有影響到docker提供的信任的鏡像, 包括官方的Ubuntu鏡像和其他的基本鏡像。

最好的選擇是本地屏蔽掉‘index.docker.io’,并且在使用‘docker load’導入到docker之前,先手動下載、驗證一下鏡像文件。Red Hat的安全論壇上有很多好的相關的帖子(https://securityblog.redhat.com/2014/12/18/before-you-initiate-a-docker-pull/)。

感謝Lewis Marshall 指出了tarsums一直沒有驗證的問題。

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!