
01 / 什麼是代碼加密?
雲端加密代碼服務是雲效團隊的自研産品,是目前國内率先支援代碼加密的托管服務,也是目前世界範圍内率先基于原生Git實作加密方案的代碼托管服務。
通過在雲端對托管在雲效Codeup的代碼庫進行落盤加密,可以有效避免資料擁有者之外的人接觸到使用者的明文資料,避免資料在雲端發生洩露。同時,代碼加密過程對使用者完全透明,使用者可以使用任意官方Git端(包括但不限于Git、JGit、libgit2等)來通路Codeup上的代碼倉庫。
02 / Linux社群重大安全性事件回顧
2011年8月底,用于維護和分發Linux作業系統的多台伺服器感染了惡意軟體,這些惡意軟體非常厲害,可以擷取root的通路權限,修改其上的系統軟體以及登入密碼。但社群的維護者稱,維護linux的源代碼,是未受到漏洞影響的。
這是為什麼呢?因為他們使用了Git進行代碼維護,對于linux核心代碼将近40000個檔案來說,每個檔案都做了hash來確定唯一性,是以很難在不引起注意情況下,更改舊的版本。
雖然Git可以解決開源社群關心的源碼篡改問題,卻解決不了企業擔心的資料洩露問題。而對于企業級代碼托管來說,今天所面臨的問題不但有資料安全、還有可靠性及成本問題。
當企業規模較小時,對可靠性要求也不高,一個自建的代碼托管服務似乎就能滿足需求。但随着規模不斷擴大,代碼量不斷增加,可能需要更好的伺服器配置,才能滿足多人協作的需求,甚至還需要投入專人維護來保證可靠性,這時就不得不思考成本的問題。
而雲代碼托管服務,有着比自建代碼托管服務更高的可靠性及更低的成本,但相比自建代碼托管服務而言,由于其并不開放底層存儲的直接通路,間接造成了使用者不可控的安全心理。
而代碼加密技術,正是通過将底層存儲的不可控變為近完全可控,解決使用者代碼上雲的顧慮。
03 / 自建真的比上雲更安全麼?
在回答這個問題之前,讓我們一起來了解一些背景知識——Git的存儲結構。
當我們使用Git進行代碼送出時,最先接觸到的便是送出記錄及分支。分支或者标簽,可以統稱為引用。它們存儲在以路徑名作為引用名,以及對應版本hash作為内容的單個檔案中。由于分支名通常與業務無關,是以可以認為,其中不包含敏感資料的。
除了送出記錄commit之外,我們的代碼檔案被存儲到blob對象,檔案名及目錄等資訊,存儲到tree對象,帶有額外的資訊的标簽被存儲到tag對象。
對象是Git中存儲資料的基本單元。通常情況下,對象存儲在以内容hash值命名的單個檔案中,我們稱之為松散對象。而通過執行gc(也就是垃圾回收)之後,這些對象就會被打包到一起,生成一個打封包件packfile。代碼内容及檔案名,都存儲在blob及tree對象當中,是以可以認為,對象中是包含使用者的代碼内容資料,也就是包含敏感資料的。
Git中的對象存儲,為了降低磁盤占用,會通過zlib進行一次資料的壓縮。換句話說,隻需通過解壓縮就可以擷取到資料内容,是以可以認為是明文存儲。也就是說,任意可以接觸到存儲的人,都可以檢視存儲上的代碼資料。
明文存儲引發的信任問題
回答前面提出的問題,正是由于Git代碼非安全存儲的特點,自建的代碼托管服務,既要防範來自外部的一些攻擊風險,還要防範内鬼,因為通常企業代碼資料洩露是從内部發生。
而對于雲代碼托管服務而言,我們可以借助阿裡雲安全,有效避免來自外部的黑客攻擊風險,那麼,如何解決使用者對雲代碼托管服務的信任問題,讓代碼對運維人員不可見呢?
引入代碼加密技術,通過使用使用者的密鑰,加密雲端托管的代碼資料,既增加了靜态存儲資料的安全性,又可以阻斷代碼對運維人員的可見性,進而消除使用者上雲的顧慮。
04 / 代碼加密技術揭秘
我把它分化三個問題去解決:
1.密鑰管理
使用一個安全合規的方式托管密鑰,密鑰存儲安全,才能保證加密安全。這個可以借助阿裡雲的密鑰管理服務KMS。
2.密鑰使用
Git是一個計算密集型的服務,如果直接使用密鑰管理服務的加解密能力,那麼這個性能是難以接受的。
那這裡還有什麼方案呢?我們可以使用信封加密技術。顧名思義,我們可以使用資料密鑰,來對我們明文的代碼資料進行加密,使用數字信封技術,保證密鑰儲存、傳輸、使用過程的安全性。由于我們隻存儲密文的資料密鑰及密文的代碼資料,必須通過使用者授權,才能完成運作态的代碼資料解密。而處于靜态存儲的代碼資料,則無法被運維人員擷取。
3.基于原生Git的加密實作
在原生Git的基礎上,通過增加代碼加密更新檔,以在實作加密的能力同時,最大程度地擷取到原生Git帶來的各種優勢。
原生Git是如圖所示的這樣一個自上而下的分層架構,和我們常見的應用架構非常類似。
最上層是展現層,包含紛繁複雜的指令行入口,直接暴露給應用服務進行調用。
中間是業務處理層,從資料内容角度,可以分為引用操作及對象操作。通過增加一個加解密的子產品,在記憶體中進行資料加密,将密文資料寫入磁盤,進而保證靜态資料的安全性。
為了擷取最高的性能,僅選擇與使用者代碼資産相關的對象資料進行加密存儲,而對于引用清單及對象索引等資料,仍維持明文存儲。利用硬體加速,代碼加密的額外性能損耗控制在10%左右,在使用者使用過程中幾乎無感。
本地Git代碼加密示範
事先準備好一個配置了代碼加密的的倉庫。這個倉庫是空的。
我們向裡面添加一個檔案。
通過
hexdump -C
檢視這個檔案的二進制内容,我們可以發現,它是以首位元組
78 01
起始,這是一個典型的經過zlib壓縮後的檔案頭。
接下來,我們開啟加密的開關,通過
git commit
建立一個加密的送出記錄。再次檢視儲存的送出記錄二進制内容,發現這時建立的對象資料不再以
78 01
開始,而是以我們指定的加密标記位開始。
注意,受時間關系,這裡我們未進行同一個對象非加密與非加密狀态下的直接對比,而是以檔案頭是否變化來判斷加密與否。
在完成松散對象加密之後,我們可以通過
git gc
,将松散對象轉換為打包對象,再看一下打包對象會發生什麼樣的變化呢?由圖中我們可以發現,加密後的打封包件標頭版本中,不再是原有的
00 00 00 02
,而是增加了特定辨別的
82 00 00 02
,并且標頭也由原有的12位元組擴充為24位元組,增加了12位元組的NONCE用于增加安全性。
那麼,當我們移除密鑰配置之後,是否可以繼續通路這個倉庫呢?
當我們移除密鑰之後,由于缺少密鑰,當我們嘗試通過
git show HEAD
檢視目前版本時,會得到一個錯誤資訊,提示未提供密鑰。
這個錯誤是基于我們在原生Git基礎上,定制化了代碼加密能力更新檔,若是沒有這個更新檔,會有什麼樣的表現呢?
針對加密的打封包件packfile,會提示目前版本較低,請更新Git版本;若針對松散對象,則提示檔案頭不正确,因為不是一個zlib的壓縮頭。
歡迎大家使用雲效代碼管理Codeup,全方位保護企業代碼資産,幫助企業實作安全、穩定、高效的代碼托管和研發管理。
點選前往雲效Codeup了解産品并使用。
加入我們
如果你是一個懂代碼,愛 Git,有技術夢想的工程師,并想要和我們一起打造世界 NO.1 的代碼服務和産品,請聯系我吧!C/C++/Golang/Java 我們都要!
(=´∀`)人(´∀`=)
If not now, when? If not me, who?
履歷投遞郵箱:[email protected]