Springboot 加密方案探討

魯道發表於2023-10-14

背景

toB 的本地化 java 應用程式,通常是部署在客戶機器上,為了保護智慧財產權,我們需要將核心程式碼(例如 Lience,Billing,Pay 等)進行加密或混淆,防止使用 jadx 等工具輕易反編譯。同時,為了更深層的保護程式,也要防止三方依賴細節被窺探;

業界方案

  1. ProGuard
    • 簡介:開源社群有名的免費混淆工具,相較於位元組碼加密,對效能基本無影響;
    • 優勢:打包階段混淆位元組碼,各種變數方法名都變成了abcdefg 等等無意義的符號,位元組碼可被反編譯,但幾乎無法閱讀,通常被 Android App 用來防止逆向;
    • 不足1:只能混淆部分程式碼,打包階段較為耗時,對於三方包混淆,並沒有什麼好辦法。
    • 不足2:混淆後的程式碼,會影響 arthas 工具的使用,導致排查問題變慢。
    • 不足3:配置比較複雜,曾經在我司 T 專案上用過,令人眼花繚亂。
    • 不足4:無法加密三方依賴所有資訊;
  2. jar-protect
    • 簡介:一款國人開發的 springboot jar 加密工具;需要配合 javaagent 解密;
    • 優勢:打包階段使用 javassist 重寫 class 檔案;jadx 反編譯後看到的都是空方法。反編譯後只能看到類資訊和方法簽名,無法看到具體內容。
    • 不足1:使用 DES 方案,對於幾百個三方 jar 的場景,加密手段過重,且加密後的不夠完整;
    • 不足2:類檔案放在一個目錄(META-INF/.encode/),非常容易類衝突;
    • 不足3:無法加密三方依賴所有資訊;
  3. GraalVM
    • 簡介:Oracle GraalVM 提前將 Java 應用程式編譯為獨立的二進位制檔案。與在 Java 虛擬機器 (JVM) 上執行的應用程式相比,這些二進位制檔案更小,啟動速度提高了 100 倍,無需預熱即可提供峰值效能,並且使用的記憶體和 CPU 更少, 並且無法反編譯。
    • 不足:無法支援我司業務程式框架。
  4. core-lib/xjar
    • 簡介:國人開源的,基於 golang 的加密工具。使用 maven 外掛加密,啟動時 golang 解密;效能影響未知。
    • 優勢:可對所有 class 檔案加密。
    • 不足1: 加密後 jar 檔案體積翻倍;
    • 不足2:依賴 golang 編譯,依賴 golang 啟動;
    • 不足3:無法加密三方依賴所有資訊;
    • 不足4:開源專案,3年未有新提交。

思考:

我們的需求到底是什麼?a:保護智慧財產權。具體手段為:

  1. 對本司專案程式碼進行加密,使其無法被 jadx 工具輕易反編譯,
  2. 對本司三方依賴進行加密,使其無法窺探我司三方依賴細節;

但上面的幾個專案,基本都是圍繞著 class 加密(除了GraalVM),這無法實現我們的第二個需求。

我們的方案

設計目標:

  1. 將專案三方依賴 jar 進行加密,使其無法使用 jadx 反編譯,但執行時會生成解密後的臨時檔案。
  2. 將專案本身的 class 進行加密,使其無法使用 jadx 反編譯執行時解密後的檔案。
  3. 加密策略要靈活,輕量,對啟動速度,包體積,記憶體消耗,介面效能的影響要控制在 5% 以內;

設計方案:

  1. 加密時,使用 maven 打包工具,repackage fat jar;將其內部 lib 目錄的依賴進行加密;使 jadx 無法反編譯;
  2. 加密時,對於核心業務程式碼,使用 javassist 工具將其重寫,清空方法體,重置屬性值;
  3. 解密jar時,將指定目錄的 加密包 解密 到指定目錄,並將其放入 springboot classloader classpath 裡。
  4. 解密class時,agent 配合判斷是否是加密 class,如果是,則尋找加密 class 檔案,找到後解密,返回解密後的 classBytes。

邏輯如下:

注意點:

  1. javassist 重寫方法體時,需要將 lib 裡的所有程式碼都加入 classpool 的 classpath 裡。
  2. javassist 加密後的類,需將其放入到當前 lib 的單獨目錄進行個例,防止類衝突。
  3. agent 解密要輕量,不能影響程式效能;
  4. 三方包的加解密重新打包後,jar 順序發生變化,較小可能會導致類衝突(比如 log4j)。需要在測試環境驗證,如果存在衝突,則需要排包。

End

透過以上方案,我們實現了一個極其輕量的 maven 加密,agent 解密外掛。他能夠將三方包徹底加密,使 jadx 等工具無法反編譯 ,遮蔽我們的三方依賴細節,同時,該外掛也可以加密我們的業務 class 程式碼,使 jadx 無法反編譯執行時生成的程式碼,從而一定程度的保護我們的智慧財產權;

另外,私有的加密演算法,在效能,體積,記憶體等方便的影響都控制在 5% 以內。

為了防止混淆後的程式碼影響 arthas 的使用和 bug patch 的應用,我們放棄了混淆方案,只能說是一種權衡與取捨吧。

從軟體防破解的角度來理解,通常只能是加大破解的難度,鐵了心想要破解的話,就算是 ProGuard 混淆,也無法解決。也許只能用 GraalVM,但不是每一個客戶都會用這個。

推薦

Java 擴充套件點/外掛系統,支援熱插拔,旨在解決大部分軟體的功能定製問題

相關文章