Docker鏡像并不安全

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

【編者的話】作者深入研究了Docker鏡像的下載流程,并逐步分析了Docker鏡像下載過程中可能出現的安全問題。關注Docker安全以及做Docker鏡像存儲的同學必看。另外,作者還總結了應該采取哪些措施來改善Docker鏡像的安全性。

最近在使用Docker下載一個“官方”容器鏡像時我看到這么一行提示:

ubuntu:14.04: The image you are pulling has been verified
我當時以為這和Docker極力推薦的鏡像簽名系統有關,所以并未深究。后來,在研究Docker鏡像安全相關的加密系統時,我開始進一步探索Docker的鏡像安全。而我發現所有與鏡像安全相關的邏輯完全是系統性的錯誤。

按照Docker的說法,下載的鏡像完全是基于簽名的manifest的存在而做出的,并且Docker并沒有從manifest中校驗鏡像的校驗和(checksum)。攻擊者可以偽造提供一個具有簽名證明的鏡像,這個問題很容易被攻擊者利用。

鏡像從HTTPS服務器上下載下來,然后通過Docker daemon的一個不安全的流處理管道:

[解壓縮] -> [tarsum] -> [解包]
這個管道很高效,但毫無安全可言。在未驗證簽名之前,管道不應該處理不受信任的輸入。然而,在驗證檢驗和之前,Docker進行了三次鏡像的處理。

盡管Docker做了聲明,但它從未實際檢查過鏡像校驗。下面是Docker中唯一一處與驗證鏡像校驗和有關的代碼,但是即便在鏡像中提供不匹配的校驗和,我也無法觸發這個警告。

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運行xz程序來解壓縮。

xz程序來自XZ Utils項目,它從接近2萬行C代碼中構建而來。C不是一個內存安全的語言。這意味著一個C程序的惡意輸入,此處為XZ Utils正在解包的Docker鏡像,有執行任意的代碼的可能。

如果Docker以root運行xz,那會更糟糕,這意味著如果xz存在一個漏洞,執行docker pull將嚴重危及你的整個系統。

Tarsum

tarsum的使用出于好意,但完全錯誤。為了取得一個任意編碼的tar文件的確定性校驗和,Docker對tar進行解碼然后以確定性順序對特定部分進行哈希,排除了其他部分。

因為這個處理過程是為了生成校驗和,它正在解碼的不受信任的數據可被設計成利用tarsum代碼的漏洞。這里可能的漏洞是拒絕服務攻擊以及邏輯缺陷,這將引起文件在不改變校驗和的情況下被注入、跳過、使用不同方式處理、修改、添加等。

解包

解包分為tar解碼和將文件到保存到硬盤中兩個步驟,在編寫本文的時候已經有解包階段的三個其他漏洞被報告出來,所以這也是非常危險的。

不應該存在未被檢驗的數據被解包到硬盤中的情況。

libtrust

libtrust是一個提供認證和權限控制的Docker包。但是官方沒有提供任何的規范,但它看起來像是實現了Javascript對象簽名與加密規范的一部分,以及其他不明算法。

所以在下載一個manifest簽名的以及使用libtrust驗證的鏡像時,會有如下不準確的提示:

ubuntu:14.04: The image you are pulling has been verified
目前只有Docker公司公布的“官方”鏡像manifest使用這個系統簽名,但從我參加的最近一次Docker管理咨詢委員會會議的討論看來,Docker公司計劃在未來更廣泛的部署它。目標應該是集中管理,由Docker公司控制一個發證機構用于鏡像和/或客戶證明簽名。

我曾在Docker代碼中查找簽名密鑰,但沒找到。看來密鑰并沒有嵌入到程序中。實際上,Docker后臺會在每次鏡像下載時通過HTTPS從CDN獲取密鑰。這是一個非常糟糕的方式,因為有很多種攻擊可以導致受信任的密鑰被替換成惡意的。這種攻擊包括但不限于:CDN供應商威脅、CDN供應密鑰源威脅以及客戶端下載密鑰時的中間人攻擊。

補救

在完成此項研究之前,我已經報告了我發現的tarsum系統的幾個問題,但至今沒有一個被修復。

我覺得必須采取一些措施來改善Docker鏡像下載系統的安全性:

棄用tarsum并實際驗證鏡像摘要

為安全起見,不應該使用tarsum。取而代之的是在進行任何處理前,將鏡像完全下載并對其加密簽名進行驗證。

增加權限隔離

涉及解壓縮或解包的鏡像處理步驟必須運行于具有最低限度的必要的權限的隔離的程序(容器?)中。不應該存在像xz這樣的解壓縮工具必須以root運行的情況。

更換libtrust

The Update Framework替換libtrust,前者是明確設計用于解決軟件程序簽名的實際問題的。它的威脅模型非常全面,并且解決了很多libtrust沒有考慮到的事情。它擁有一個完整的規范,以及一個Python的參考實現,我已經開始Go的實現并且歡迎任何人加入。

作為添加TUF到Docker的一部分,一個映射根密鑰到registry URL的本地密鑰庫將被加入,以便用戶可以使用不受Docker公司管理的自有簽名密鑰。

我想指出的是,一般情況下使用非Docker公司托管的registry用戶體驗非常差。在沒有任何技術原因的情況下,Docker公司似乎樂于將第三方registry降低為二等地位。這對一般的生態系統和最終用戶的安全來說都是個問題。綜合而言,針對第三方registry的分散的安全模型是必要和可取的。我非常期待Docker公司在重新設計他們的安全模型和鏡像驗證系統時考慮這一點。

結論

Docker用戶應該清楚負責下載鏡像的代碼是極其不安全的。用戶只能下載那些來源沒有問題的鏡像。目前,這不包括托管于Docker公司的“可信的”的鏡像,包括官方的Ubuntu和其他基礎鏡像。

最好的辦法是在本地阻止index.docker.io,并在鏡像導入到Docker之前手動使用docker load下載并檢驗鏡像。Red Hat的安全博客有篇與此相關的好文章

感謝Lewis Marshall指出tarsum從未被驗證。

原文:Docker Image Insecurity
來自:http://dockerone.com/article/77

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