如何保證 Java 應用安全?標準答案來了 | 龍蜥技術

OpenAnolis小助手發表於2023-04-07

文/ 林子熠,雲原生機密計算 SIG Maintainer

“請問我怎麼才能保證 Java 程式記憶體中密碼的安全呢?”

如果你也過有類似的問題,並且在網上搜到一些並不十分完善卻又無可奈何的答案,說明你就是 Java 程式安全性問題的 stakeholder。

這個問題的標準答案是 Java 機密計算技術,它將機密計算技術引入 Java 的世界,為 Java 程式的安全性帶來了重大的提升。基於此,龍蜥社群雲原生機密計算 SIG 推出了 Java 機密計算的具體實現技術——Teaclave Java TEE SDK, 以下簡稱 Teaclave Java。該技術具有以下顯著優點:

  • 全場景安全性。當使用者有機密計算硬體支援時,Teaclave Java 可以實現最高安全等級的 Java 可信計算;當使用者沒有相關硬體時,退化為安全沙箱隔離級別的可信計算,亦可有效保護使用者的敏感資料和計算過程的安全性。

  • 開發和構建簡單。基於 SPI 的純 Java 程式設計模型,一鍵式構建,將 Java 機密計算開發構建門檻一降到底。

Teaclave Java 已經過企業級內部場景的驗證,在 Apache 社群開源。描述本技術的論文由龍蜥社群雲原生機密計算 SIG 與上海交通大學、大連理工大學合作發表在軟體工程頂會 ICSE 2023()上,並且獲得了本屆會議的 ACM SIGSOFT 傑出論文獎。這是 2020 年以來,龍蜥社群雲原生機密計算 SIG、上海交通大學、大連理工大學首 次獲此殊榮。

01 問題的本質

這個問題的本質是如何在具有風險的執行時環境中安全地使用敏感資料。當我們在執行時將密碼解密後,密碼就會以明文的形式存在於記憶體中,也就是 Java 的堆上,如圖 1 的左半部分所示。如果系統遭受攻擊,比如 2021 年聲名大噪的 log4j 漏洞攻擊,Java 堆上的內容就會被竊取。即便沒有被攻擊,在為了效能診斷而做 heap dump 時也有可能主動將敏感資訊洩漏出去。所以將諸如密碼這樣的安全敏感資訊暴露在普通執行環境具有高度的風險。

如何保證 Java 應用安全?標準答案來了 | 龍蜥技術

(圖 1 樸素的 Java 密碼保護示意圖)

一種保護思路是儘可能地縮短明文密碼在記憶體中的存放時間,以縮短敏感資訊暴露的時間視窗。如圖 1 右半部分所示,在使用完密碼後,及時將其從記憶體中銷燬,這樣會比先前更加安全一些。因為密碼是文字資訊,會用字串類 java.lang.String 儲存。Java 的 String 是一種 immutable 型別,建立後不能更改內容,所以沒有可以重置內容的 API。要銷燬密碼只能透過反射將 String 類內部儲存字元內容的陣列內容置空,從而將密碼內容從 Java 堆上抹去。直接將密碼字串設定為 null 是沒有用的,這樣只是把 String 變數的指標設為空,對於 Java 堆上的密碼資料沒有任何影響,只有等到下次垃圾回收時才有可能將密碼資料從堆中清除。另一種方法是用 char 陣列儲存密碼,而不是 String 類,這樣就不必呼叫反射,讓銷燬更加便利。還有一種方法是用 byte 陣列儲存密碼,因為其明文是字元編碼而非人可讀的字元,所以會更難被人看懂。

這些就是目前可以從網路上搜到的解決方法,本文將它們稱為“樸素”的 Java 密碼保護方案。因為這些方案只是縮短了明文密碼在 Java 堆上的生存時間,並沒有真正將明文密碼保護起來。而且“及時”一詞有很大的彈性,開發人員未必能準確地判斷出何時才是及時。

更具有典型性的案例就是著 名的 log4j 漏洞問題()。攻擊者可以利用 log4j 2.14 的漏洞將惡意 class 檔案上傳到伺服器並透過 Java 的動態類載入機制執行,從而竊取 Java 堆中儲存的伺服器私鑰。有了私鑰,伺服器與客戶端之間的所有通訊內容對於攻擊者都如同明文了。

在以上兩個例子中,需要在執行時保護的密碼和金鑰都是安全敏感的資料。而在實際場景中,保護範圍並不僅限於敏感資料,還有可能擴大到運算過程。比如鑑權認證場景中,需要保證認證的過程可信,不能被攻擊者篡改。再比如雲服務的使用者將自己的演算法部署上雲時,雖然部署的製品可以加密,以保護傳輸和儲存時的安全,雲廠商提供了固若金湯的安全防護以免受外部攻擊,但是使用者依然會擔心雲廠商有沒有在執行時窺探使用者的計算過程,是否存在監守自盜的可能。

由此可見,保護 Java 應用中的安全敏感資料和運算並不是一件遙遠的需求,而是具有迫切的現實意義的需求。對於雲端計算的供應商,讓使用者相信其敏感資料和運算對於雲廠商自己也是不可見的黑盒亦具有重大的商業價值。

02 Java 機密計算(Confidential Computing)現狀

保護執行時的敏感資料並不是一個新鮮話題,而屬於迄今已發展了 20 多年的技術——機密計算的一部分。機密計算是一種提供硬體級的系統隔離,以保障資料安全和程式執行安全的技術。機密計算將執行環境劃分為富執行環境(Rich Execution Environment,REE)和可信執行環境(Trusted Execution Environment, TEE),認為 REE 和 TEE 應該相互隔離,TEE 需要透過硬體加密以保證外界無法知曉其中的內容。安全敏感的內容應該放在 TEE 中執行,其他內容則在 REE 中執行。

這套機制早在 1999 年就已提出,不過早期的硬體加密技術能力有限,僅有支援執行加解密程式的 TPM(可信任的平臺模組,Trusted Platform Module)硬體。2008 年 Arm 釋出 TrustZone 技術白皮書,以支援 Arm 平臺的通用型機密計算任務。2015 年Intel也推出了帶有支援通用應用加密的 SGX(軟體保護擴充套件,Software Guard Extension)晶片的硬體裝置,2021 年 SGX 升級為可支援 1T 記憶體、具有更高效能的SGX2。

機密計算的核心理念是在具有被攻擊風險的執行時環境中提供一塊安全區域供安全敏感程式執行,實現了安全敏感資料和程式在傳輸、儲存和計算全流程的安全可信。目前機密計算在隱私安全、區塊鏈、多方計算、IoT 和邊緣裝置,以及個人計算裝置上均有廣泛的應用和廣闊的前景。

看起來機密計算技術正是解決 Java 程式安全性問題的標準答案,那麼我們是否能夠在 Java 應用中應用機密計算技術呢?

Occlum – 在 TEE 中放入 JVM 和應用整體

SGX、TrustZone 等為通用型機密計算提供了硬體基礎,Intel、微軟等開源的驅動和SDK 則為通用型機密計算提供了軟體基礎。基於這些軟硬體基礎,開發者已經可以在軟體應用中使用機密計算。但是機密計算對於 Java 應用並不友好,因為 TEE 中只能執行 native 程式,所以 Java 程式並不能直接執行於 TEE 中。要在 TEE 中執行 Java 程式,就必須先在 TEE 中啟動一個JVM,然後在 JVM 上執行 Java 程式。那麼是否能在 TEE 中執行 JVM 呢?答案是肯定的,那就是 Occlum,其原理如圖 2 所示。

Occlum 是介於 TEE 底層 SDK 與 JVM 之間的一層 LibOS,作為作業系統支援普通 JVM 在 TEE 中的執行。使用者將包含了機密程式碼在內的整個 Java 程式部署在 TEE 中,由 Occlum 支援 JVM 執行。圖 2 右半部分給出了部署的結構,其中黃色的 APP 代表整個 Java 應用及其所需三方庫,紅色圓圈代表可信程式碼。應用透過 REE 中的啟動器——通常只是一個很小的命令列工具,啟動執行。這種方案的相容性好,使用者基本不需要修改原有程式碼即可獲得機密計算支援。但是缺點也很明顯——放入 TEE 的程式碼太多,會導致兩個問題:

  1. 安全性下降。原本需要在 TEE 中執行的可信程式可能並不多,但是此方案需要將所有的 Java 程式、三方庫、JVM 和 LibOS 全部放入 TEE,導致 TCB(可信計算基,Trusted Computing Base)太大,安全性並不理想。TCB 是安全領域衡量安全性的重要指標,指信任的程式碼量。TCB 越大,其中可能存在安全隱患的程式碼就越多,程式的安全性就越差,所以 TCB 越小越好。以 log4j 攻擊為例,Occlum 仍然無法對其免疫。因為 log4j 庫與機密程式碼並沒有被分隔在不同的執行環境中,而都部署在 TEE 中,所以攻擊者上傳的惡意類檔案也會位於 TEE 中,仍然可以從記憶體中訪問到私鑰。

  2. 效能下降。TEE 的硬體不是通用硬體,與 REE 相比存在效能退化,所以將應用整體放入 TEE 中會導致整個應用的效能下降。但使用者原本的需求只是區域性加密,為了區域性加密而導致整體效能下降會增大應用機密計算的成本。雖然一般使用者可以接受為了安全而產生的部分效能退化,但是對於過度加密產生的額外效能退化會感到難以接受。

如何保證 Java 應用安全?標準答案來了 | 龍蜥技術

(圖 2 Occlum 原理示意圖)

綜上可見,Occlum 方案雖然具有簡單易行的優勢,但是其在安全性和效能方面的缺點卻是其投入實際應用的主要障礙。

03 Teaclave Java TEE SDK – 在 TEE 中僅放入可信程式碼

因為在 TEE 中整體支援 JVM 和全部應用程式的方案會在 TEE 中執行過多的程式碼,導致安全性和效能下降而難以投入實用,能不能換種思路,僅將可信程式碼放入 TEE 呢?考慮到 TEE 中只能執行 native code,那麼是不是可以將可信程式碼從 Java 程式碼直接編譯為 native code 放入 TEE 執行呢?答案是肯定的,這就是本文的主角Teaclave Java TEE SDK,以下簡稱Teaclave Java。

Teaclave Java 是由 JVM 團隊開發的 Java 機密計算開發框架和構建工具鏈,可以一站式快速實現 Java 機密計算應用的開發和構建。退一步考慮,即使使用者沒有支援機密計算的硬體環境,Teaclave Java 也可以實現安全沙箱隔離,有效保障敏感資料和程式的執行時安全。

Teaclave Java 的關鍵技術特性有:

1)模組分隔、機密計算服務化,如圖 3 所示。

2)簡潔完善的機密計算服務生命週期管理API。

3)Java 靜態編譯機密內容。

4)隱藏實現細節、自動生成所有輔助程式碼。

在這些技術的支援下,Teaclave Java 能夠將從普通模組到機密模組的 Java 模組間服務呼叫轉為從普通模組到機密 native 庫的函式呼叫,如圖 4 所示。

模組分隔、機密計算服務化

Teaclave Java 將應用程式碼分為三個模組,Host、Enclave 和 Common。Host 中是普通的安全非敏感程式,Enclave 中是安全敏感程式,Common 中則是前兩者都會用到的公共程式碼。這種模組劃分方式一是為了讓開發者感知到程式碼的安全性區分,二是為了構建時針對不同模組使用不同工具鏈的便利性。

Host 和 Enclave是解耦合的,它們之間只能透過 Java 的 SPI(Service Provider Interface)機制互動,而不能直接呼叫。機密計算的實現在 Enclave 模組中被封裝成為了服務,其介面宣告定義在 Common 模組中,並用@EnclaveService 註解標識。當 Host 中的程式需要用到某一機密計算任務時,就可以先載入服務例項,再呼叫相應的函式。這一結構組織關係如圖 3 所示。

如何保證 Java 應用安全?標準答案來了 | 龍蜥技術

(圖 3 Teaclave Java 的開發檢視)

例如我們可以在 Common 中宣告一個如程式碼塊 1 所示的機密計算服務介面,其中提供了用於認證加密的密碼是否有效的 API,authenticate 函式。該函式接受一個使用者傳入的加密的密碼,返回該密碼的認證結果。

@EnclaveService
public interface AuthenticationService {
    /**
     * Given an encrypted input password, check if it is the correct password.
     * @param inputPwd the encrypted password to be authenticated
     * @return true if the given password is correct.
     */
    boolean authenticate(String inputPwd);
}

(程式碼塊 1 在 Common 模組定義機密計算服務介面宣告示例)

AuthenticationService 介面的具體實現則在 Enclave 模組的 AuthenticationServiceImpl 類中定義,如程式碼塊 2 所示。該類的 authenticate 函式先使用私鑰對輸入的加密字串解密,獲得明文結果,然後將其和記憶體中儲存的正確的密碼比對,再返回是否一致的檢查結果。該類中儲存的正確密碼值和私鑰都是安全敏感資料,authenticate 函式的實現也是安全敏感運算。它們都將在 TEE 中執行,以黑盒的形式提供給外部使用。從外部只能看到加密的輸入資料和返回的判定結果,而無法窺探到實際的執行過程和資料。

public class AuthenticationServiceImpl implements AuthenticationService {
    private String pwd = "somePwd"; // assume it's got at runtime.
    @Override
    public boolean authenticate(String inputPwd) {
        String decryptedInputPwd = decrypt(inputPwd);
        return pwd.equals(decryptedInputPwd);
    }
    private static String decrypt(String inputPwd) {
        return inputPwd; // assume it's decrypted with private key
    }
}

(程式碼塊 2 在 Enclave 模組定義機密計算服務介面實現示例)

Host 模組使用機密計算服務的程式碼示例如程式碼塊 3 所示,從中可以看到對機密計算服務 AuthenticationService 介面的使用和普通的 SPI 介面別無二致,依然是載入服務、呼叫函式、根據結果執行不同的動作等過程。稍有區別的地方在於先要建立出機密計算環境 Enclave 的例項,然後從中載入機密計算服務例項,由此將機密計算的服務例項和環境例項繫結,最後再銷燬環境。這些機密計算環境生命週期管理的 API 由Teaclave Java 提供。從程式碼塊 3 中可見,在 Host 模組中無需感知密碼和私鑰究竟是什麼,也不用瞭解認證的過程,只是將認證函式當作黑盒服務呼叫。

public class Main {
    public static void main(String[] args) throws Exception {
        Enclave enclave = EnclaveFactory.create();
        Iterator<AuthenticationService> services = enclave.load(AuthenticationService.class);
        String pwd = "encryptedPwd"; // assume this is an encrypted password
        while (services.hasNext()) {
            AuthenticationService authenticationService = services.next();
            if (authenticationService.authenticate(pwd)) {
                System.out.println("Passed");
            } else {
                System.out.println("Rejected");
            }
        }
        enclave.destroy();
    }
}

(程式碼塊 3 從 Host 模組使用機密計算服務示例)

以上三部分程式碼就構成了一個完整的 Java 機密計算應用。從開發的角度看起來與編寫一個普通的 SPI 服務呼叫的應用基本一樣,只需要專注於業務邏輯的開發即可,並不需要學習機密計算底層的內容。因此 Teaclave Java 將 Java 機密計算的開發門檻降低到了 0。

構建機密計算應用

Teaclave Java 提供了一套完整的構建工具鏈以支援上文所述的程式設計模型,使用者只需輸入幾個簡單的 maven 命令即可完成全部構建任務。構建工具鏈將非機密程式碼和機密程式碼分別編譯為 Java bytecode 產物和可部署於 SGX 中的 native 庫,以及自動生成完成機密計算服務呼叫所需的所有的輔助程式碼。

圖 4 展示了 Teaclave Java 的構建部署檢視,主要包括三方面內容:

1)Host 和 Common 模組被編譯為普通的 Java bytecode,部署在普通環境中執行。

2)Enclave 和它所使用到的 Common 模組中的內容被編譯為 native 機密庫檔案,部署在 SGX 硬體中執行。

3)從 Java bytecode 到 native code 之間並不能直接呼叫,而需要一些適配轉換工作,包括:

  • 服務代理:透過J ava 的動態代理機制將Host模組中的機密計算服務呼叫代理到實際的native函式上,並完成上下文環境的同步、服務引數和返回值的序列化反序列化等工作。

  • JNI 層:Java 側的 native 函式宣告、native 側的 JNI 函式宣告和到機密庫函式的呼叫等輔助程式碼。

如何保證 Java 應用安全?標準答案來了 | 龍蜥技術

(圖 4 Teaclave Java 部署檢視)

這些適配轉換呼叫的程式碼在構建中被自動生成,分別部署在普通環境和 SGX 中,在圖 4 中它們被用藍色標出。

構建過程中的重要一步是將機密部分的 Java 程式碼編譯為 native 程式碼的 Java 靜態編譯。

Java 靜態編譯

Java 程式原本需要在 JVM 上才能執行,但是 Java 靜態編譯技術可以將 Java 程式(包括JDK庫依賴和三方庫依賴)加上必要的執行時支援程式碼一起編譯為 native 程式碼,然後直接執行。以此實現了 Java 程式無需 JVM 的輕量級執行。

Teaclave Java 採用了目前最成熟的 Java 靜態編譯技術——Oracle 主導的開源專案GraalVM 進行 Java 靜態編譯。GraalVM 首先對 Java 程式做可達性分析,找到從程式入口開始的所有可能執行到的程式碼範圍,然後僅編譯這些可達的程式碼,得到一個native 製品(被稱為 native image)。程式入口對於可執行程式來說是 main 函式,對於庫檔案來說是暴露的公共 API。具體到 Teaclave Java 場景,入口就是開發者定義的機密計算服務函式,也就是 Enclave 模組中定義的機密計算服務介面的實現函式。這些介面實現會用到三種依賴,Common 模組中的程式碼、某些 JDK 庫以及其他Java 三方庫,但是隻會用到這些依賴的部分程式碼,而非全部程式碼。GraalVM 就會將實際用到的程式碼分析出來,與機密計算服務的實現程式碼和 GraalVM 提供的執行時支援(被稱為Substrate VM)一起編譯為 native image。但是 GraalVM 是面向通用場景和硬體平臺的,所以 Teaclave Java 為其額外提供了針對 SGX 硬體平臺的適配和機密計算需求的最佳化。當我們編譯出 native image 後,會發現其具有了一些特別的性質:

  • TCB 下降。GraalVM 僅編譯從機密計算服務入口可達的程式碼,因此與 Occlum 將LibOS、JVM 和 Java 應用全部放入 TEE 的方案相比,TCB 大幅降低了。

  • 安全性提升。Native image 在執行時有自己的 native 記憶體堆,它與 Java 堆是相互隔離的,從 Java 應用中很難被訪問到(Java 透過 Unsafe 介面依然可以訪問 native 記憶體,但是難度提升很多)。而且 Java 靜態編譯去掉了 Java 的動態特性,只有在編譯時經過顯式配置的反射和動態類載入才會生效,其他執行時的動態行為是無效的。Log4j 漏洞攻擊在 native image 上本身就是無效的。因此native image可以被視作一個安全沙箱,即使沒有 SGX 硬體環境,native image 相比 Java 程式也提升了安全性。部署在 SGX 裡之後,TEE 的安全性會更高,因為消除了Java動態特性對 TEE 安全性的威脅。

  • 效能提升。GraalVM 的 Java 靜態編譯對程式碼有相當程度的編譯最佳化,其執行時效能大致可以達到 JVM 的 C1 最佳化水平,再加上無需啟動 JVM、沒有類載入過程、沒有解釋執行、沒有 JIT 消耗資源等等,在執行短小的任務時與 Java 程式相比能有 1 個數量級的效能提升,記憶體也有大幅削減。

這些性質可以有效地提升機密程式的安全性,提升了 Teaclave Java 的實用性。

04 Teaclave Java 技術評估

以上介紹了 Teaclave Java 提供的 Java 機密計算程式設計模型和採用的構建方式等技術問題,那麼最終實現的效果如何呢?本文以 log4j 漏洞攻擊為例分析 Teaclave Java 的功能有效性。

在 TCB 改進和執行時效能分析方面,我們準備瞭如表格 1 所示的 10 個測試。前 4 個“app-”字首的是我們自己寫的簡單應用,將它們當作機密程式,以各自的 main 入口當作普通程式。後 6 個“ct-”字首的用例則採用了著 名開源加密框架 BouncyCastle ()的單元測試,我們提供了單一入口呼叫這些測試,將測試入口當作普通程式,單元測試當作機密程式。

(表 1 / 測試用例描述)

Java 機密計算框架則採用了 OcclumJ 和 Teaclave Java 進行對比。OcclumJ 是我們實現的一種介於 Occlum 和 Teaclave Java 之間的機密計算模型,採用 Teaclave Java 的模組化和機密計算服務化的模型,但是不做 Java 靜態編譯,而是在 TEE 中以 Occlum 方式執行機密計算服務。

功能有效性評估

圖 5 給出了 log4j 漏洞攻擊的原理示意(a 子圖)和 Teaclave Java 防範 log4j 漏洞攻擊的原理(b子圖)。對於一個普通的 Java 應用服務,它和客戶端透過三個步驟互動。

1)客戶端從服務端獲取公鑰。

2)客戶端用公鑰對訊息加密,然後將密文傳送給服務端。

3)服務端從執行時記憶體中拿出私鑰解密訊息,然後再處理訊息內容。假設服務端使用了 log4j-2.14.x 版本做日誌記錄,其中的漏洞允許攻擊者誘導 log4j 從遠端伺服器下載指定的惡意 class 檔案(圖 5-a中的步驟4、5、6),然後動態載入惡意類,從 Java 堆記憶體上獲取到私鑰(步驟7)傳給攻擊者。

有了伺服器的私鑰,伺服器和客戶端之間的所有通訊對於攻擊者而言都如同明文了。

如何保證 Java 應用安全?標準答案來了 | 龍蜥技術

a. log4j 漏洞攻擊示意 (圖 5 / Java 機密計算保護應用免 受Log4j 漏洞攻擊示意圖)

如何保證 Java 應用安全?標準答案來了 | 龍蜥技術

b. 透過機密計算免疫 log4j 漏洞攻擊示意 (圖 5 / Java 機密計算保護應用免 受Log4j 漏洞攻擊示意圖)

圖 5-b 展示了 Teaclave Java 如何保護應用服務端免受 log4j 漏洞攻擊的威脅。Teaclave Java 將應用的普通程式碼放在 REE 中,安全敏感的解密和私鑰放在 TEE 中,客戶端送來加密訊息會被 REE 中的代理服務轉到 TEE 中進行解密。此時當攻擊者發起 log4j 攻擊時,因為 Log4j 部署在 REE 中,惡意程式碼也只能在 REE 中執行,而無法拿到 TEE 記憶體上的私鑰,攻擊失效。假如機密程式碼也使用了 log4j 記日誌,導致 log4j 執行在 TEE 中執行會發生什麼呢?此時 log4j 將攻擊者惡意程式碼下載到了 TEE 中,但是因為 Teaclave Java 採用了 Java 靜態編譯技術,惡意程式碼在編譯時是未知的,不會被編譯到 native image 中。而 Java 靜態編譯技術並不支援對 native image 中不存在的程式碼進行動態載入執行,所以即便惡意類被下載到了 TEE,也不會被執行。因此在這種場景下 Teaclave Java 支援的機密計算依然是安全的。但是如果採用了 Occlum 方案,因為 TEE 中有了 JVM,就可以動態載入惡意程式碼並執行,攻擊就會成功。

再退一步,當在沒有 SGX 硬體為TEE加密時,native image 依然是一個 native 沙箱,惡意 Java 程式碼無法輕易從 native 記憶體中拿到安全敏感內容。

TCB 評估

因為 Teaclave Java 不再需要 LibOS 和 JVM,機密程式碼部分也是按需編譯部署。OcclumJ 方案雖然採用了分模組模型,但是並沒有做靜態分析,因此只是模組級別的程式碼劃分,雖然較 Occlum 完全不劃分有所改進,但是與 Teaclave Java 函式級的劃分相比仍有相當大的差距。圖 6 展示了 OcclumJ 和 Teaclave Java 放入 TEE 的二進位制編譯產物的大小對比。藍條是 OcclumJ 的結果,橙條是 Teaclave Java 的結果,圖中的 Lejacon 是 Teaclave Java 在論文中的代號。

如何保證 Java 應用安全?標準答案來了 | 龍蜥技術

(圖 6 Occlum 和T eaclave Java 方案的 TCB 比較。Lejacon 是 Teaclave Java 在論文中的代號)

由圖 6 中的對比資料可見,Teaclave Java 的編譯後 TCB 大小僅為 Occlum 的大約1/20 到 1/10。考慮到編譯時 native 程式碼的膨脹問題,兩者實際的函式數量差距更大,所以 Teaclave Java 的 TCB 低於 Occlum 一個數量級,從而具有了更高的安全性。

執行時效能評估

因為 native image 會直接以 native 程式碼的形式執行,省去了包括 JVM 啟動、類載入、解釋執行等步驟的 Java 程式的冷啟動過程,所以啟動速度會非常快。如果要執行的機密程式碼較少,會很快執行完畢。但是 native image 的程式碼編譯質量不如 JVM 的 C2,所以當程式執行的時間足夠長,Java 程式碼被 JIT 充分編譯後,native image 的執行時效能就會隨著時間的增長而與 Java 程式越來越接近,然後被超越。所以 Teaclave Java 在小型應用的效能遠優於 OcclumJ,但是在長時間執行的應用方面該優勢就會縮小。

圖 7 就展現出了這一特點。圖中的藍線是機密程式碼部分採用 OcclumJ 模型的執行時間,黃線是採用 Teaclave Java 模型的執行時間,綠線是在普通環境中在普通 JVM 上直接執行的時間。程式在 TEE 中執行的時間要大於普通環境,主要因為增加了機密環境的建立、機密記憶體的分配等開銷,我們將其統稱為機密環境開銷。黃線在執行時間較短的場景中保持了與綠線接近的效能,說明 Java 程式冷啟動的開銷與 native image 的機密環境開銷差不多可以相抵。當程式執行時間較長時,冷啟動開銷被攤薄,但是機密環境開銷與TEE記憶體使用量成正比,所以黃線較綠線在最後三個測試用例上的上升線條更陡峭。

圖 8 給出了 OcclumJ 和 Teaclave Java 的執行時記憶體使用量對比。OcclumJ 的記憶體消耗包括 LibOS、JVM 和應用三部分,而 Teaclave Java 模型的記憶體消耗只有應用和 native image 中的輕量級執行時。更簡化的結構為 Teaclave Java 模式的機密計算帶來了更少的記憶體消耗。

如何保證 Java 應用安全?標準答案來了 | 龍蜥技術

(圖 7 OcclumJ 和 Teaclave Java 執行時效能對比圖。Lejacon 是 Teaclave Java 在論文中的代號)

如何保證 Java 應用安全?標準答案來了 | 龍蜥技術

(圖 8 / OcclumJ 與Teaclave Java的執行時記憶體消耗對比圖。Lejacon 是 Teaclave Java 在論文中的代號)

05 總結

Teaclave Java 是一個使用簡單、效果顯著、效能良好的 Java 機密計算解決方案,能夠幫助使用者徹底解決保護 Java 應用中的安全敏感內容和運算的問題。Teaclave Java 具有硬體寬容性,當具備 SGX 硬體環境時,可以使 Java 使用者也能像其他 native 語言使用者一樣享受到機密計算帶來的最高等級執行時安全保護;在缺少機密計算的硬體環境時,仍然可以提供安全沙箱對機密程式碼實施記憶體隔離,以避免安全敏感內容直接暴露。可以說,Teaclave Java 就是保護 Java 應用中敏感資料和運算安全的標準答案。

Oracle 已經把 GraalVM 的 Java 靜態編譯技術貢獻給了 OpenJDK,預計在 JDK 21 會合入 OpenJDK 主幹。因此在未來 Teaclave Java 方案就可以獲得 JDK 的原生支援。我們也計劃向 Java 社群提交關於增加機密計算規範的檔案,希望可以將 Teaclave Java 的機密計算模型上升為Java原生的機密計算方案。

本技術發表的論文為:Xinyuan Miao, Ziyi Lin, Shaojun Wang, Lei Yu, Sanhong Li, Zihan Wang, Pengbo Nie, Yuting Chen, Beijun Shen, He Jiang. Lejacon: A Lightweight and Efficient Approach to Java Confidential Computing on SGX. ICSE 2023.

相關連結可移步龍蜥公眾號(OpenAnolis龍蜥)2023年4月6日相同推送檢視。


—— 完 ——


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70004278/viewspace-2944471/,如需轉載,請註明出處,否則將追究法律責任。

相關文章