
一、序
在將 App 釋出到市場之前,很重要的一個步驟就是為 APK 進行簽名,大部分時候,這個操作隱藏在了打包的流程中,而不被我們注意到。
簽名的作用,除了證明 App 的所有權之外,還可以幫助 Android 市場和裝置校驗 APK 的正確性
Android 簽名是自證明的,並不會對證照進行 CA 認證。也就是我們可以使用工具自行生成簽名證照,只要是一個正確的簽名,系統就會承認,並且允許安裝。
生成簽名的時,可以指定一個有效時間,這個時間預設為 25 年,並且 Google Play 也有硬性規定,上架的 App 簽名有效期必須在 2033-10-22 日期之後。所以只要不是手欠修改了這個有效期,在當下這個時刻,是不會有問題,畢竟到現在還沒有一款 App 存在 25 年。
有些問題不在眼前,卻是真實存在的。對於一款上架的 App,最重要的就是使用者,而當簽名失效之後,我們只能被迫換籤名,此時因為簽名校驗無法通過,就會導致舊使用者無法覆蓋安裝。這些歷史使用者唯一的選擇,就是解除安裝後重新安裝。
好在這不僅僅是你我的問題,天塌下來有個子高的頂著,所以別擔心,Google 已經著手在解決這個問題了。
方案就是 Android 9.0 新增的對 APK V3 簽名的支援。
二、新的簽名方案 V3
2.1 Android 的簽名方案
Android 的簽名方案,發展到現在,不是一蹴而就的。Android 現在已經支援三種應用簽名方案:
- V1 方案:基於 JAR 簽名。
- V2 方案:APK 簽名方案 V2,在 Android 7.0 引入。
- V3 方案:APK 簽名方案 V3,在 Android 9.0 引入。
V1 到 V2 是顛覆性的,為了解決 JAR 簽名方案的安全性問題,而到了 V3 方案,其實結構上並沒有太大的調整,可以理解為 V2 簽名方案的升級版,有一些資料也把它稱之為 V2+ 方案。
因為這種簽名方案的升級,就是向下相容的,所以只要使用得當,這個過程對開發者是透明的。
V1 到 V2 方案的升級,對開發者影響最大的,就是渠道簽署的問題。在當下這個大環境下,我們想讓不同渠道、市場的安裝包有所區別,攜帶渠道的唯一標識,這就是我們俗稱的渠道包。好在各大廠都開源了自己的籤渠道方案,例如:Walle(美團)、VasDolly(騰訊)都是非常優秀的方案,想了解的可以先看看之前的文章:《Android 簽名和多渠道打包原理》。
2.2 簽名的歷史
先從 Android 簽名的歷史講起。
在上個世紀 80 年代,Phil Katz 建立了 ZIP 格式,可以將檔案和一些元陣列,組合在一個檔案中,便於傳輸和存檔,該格式是為了解決壓縮、校驗和冗餘頭等問題而提出的解決方案。

Sum 公司在上世紀 90 年代,將 ZIP 作為 JAR 格式的基礎,而 JAR 本質上就是一個 ZIP 存檔。在其中,META-INF 目錄下會包含一些後設資料和簽名資料等資訊。

Android 出現後,也沿用了 Java 的 JAR 的釋出方式,將 APK 建立在 JAR 格式之上,在此基礎上對 Dalvik 位元組碼 classes.dex 和資源 resources.arsc 等檔案新增更多標準化的結構。當時 Android 的 APK 完全依賴 JAR 的簽名方案來確保應用程式的正確性,這就是我們俗稱的 V1 方案(JAR 方案)。
在 V1 簽名方案中,並不會保護 APK 內的所有檔案,會存在一些例外部分,即便被修改也不會導致簽名失效,例如:ZIP 後設資料。同時,V1 方案對 APK 內部被保護的原始檔案,是單獨進行計算資料摘要的,所以在驗證時,需要先解壓再驗證,導致安裝時會花費更多的時間,消耗更多的記憶體。例如 V1 方案中籤渠道的方式就是利用了此特性,將渠道資訊寫入 META-INF 檔案中,這不會破壞 V1 簽名。

多年後,在 Android 7.0 中新增了一種新的簽名方式,就是我們俗稱的 V2 方案。V2 簽名提供了更強大的 APK 檔案驗證,它不再檢查包內單個檔案,而是檢查整個 APK。它在 ZIP 檔案中,插入一個額外的簽名塊,覆蓋 ZIP 檔案中的其餘部分。

在這個額外的簽名塊(Apk Signature Block V2)中,會對當前 APK 的其他部分簽名。
從安全的角度 V2 會比 V1 更安全,V2 簽名是驗證整個打包後的 APK 檔案,所以對其 APK 檔案做“任何”改動都會破壞簽名。注意這裡的任何是帶引號的,V2 簽名的簽名塊其實是一個 K-V 的結構,可以向其中插入一些簡單的資料而不破壞 V2 簽名,這就是 V2 方案下,多渠道的方案思路。
在引入 V2 方案的同時,也保證了向後相容,舊的 JAR 簽名方案仍然在舊的裝置(Android 7.0 以下)中生效,而在較新的裝置上,也會判斷是否使用 V2 簽名,不是則依然會去校驗 V1 簽名。
V2 方案解決了安全問題以及安裝時驗證的效率問題,但是它並沒有解決前面提到的換籤名問題。
2.3 Android 的 V3 方案
Android 9.0 中引入了新的簽名方式,它的格式大體和 V2 類似,在 V2 插入的簽名塊(Apk Signature Block V2)中,又新增了一個新快(Attr塊)。
在這個新塊中,會記錄我們之前的簽名資訊以及新的簽名資訊,以金鑰轉輪的方案,來做簽名的替換和升級。這意味著,只要舊簽名證照在手,我們就可以通過它在新的 APK 檔案中,更改簽名。

V3 簽名新增的新塊(attr)儲存了所有的簽名資訊,由更小的 Level 塊,以連結串列的形式儲存。
其中每個節點都包含用於為之前版本的應用簽名的簽名證照,最舊的簽名證照對應根節點,系統會讓每個節點中的證照為列表中下一個證照籤名,從而為每個新金鑰提供證據來證明它應該像舊金鑰一樣可信。
這個過程有點類似 CA 證照的證明過程,已安裝的 App 的舊簽名,確保覆蓋安裝的 APK 的新簽名正確,將信任傳遞下去。
2.4 V3 簽名的驗證過程
Android 的簽名方案,無論怎麼升級,都是要確保向下相容。
在引入 V3 方案後,Android 9.0 及更高版本中,可以根據 APK 簽名方案,V3 → V2 → V1 依次嘗試驗證 APK。而較舊的平臺會忽略 V3 簽名並嘗試 V2 簽名,最後才去驗證 V1 簽名。
整個驗證的過程,如下圖:

需要注意的是,對於覆蓋安裝的情況,簽名校驗只支援升級,而不支援降級。也就是說裝置上安裝了一個使用 V1 簽名的 Apk,可以使用 V2 簽名的 Apk 進行覆蓋安裝,反之則不允許。
三、總結時刻
Android 簽名替換的問題,Google 已經在考慮了,9.0 新增的 V3 簽名方案就是為了解決簽名替換的。這些,肯定都是提前準備。
簽名過期的問題,不需要太擔心,我們只需要跟著 Google 的步伐就可以了。
最後小結一下結論,簽名過期的問題,在 Android 9.0 上新支援的 V3 簽名,已經有解決的方案了。另外:
- V1 簽名遵循 JAR 的簽名方式,單獨驗證 APK 壓縮包中的檔案。
- V2 簽名是針對 APK 檔案的驗證,將簽名資訊寫入簽名塊中,增強了安全性和驗證效率。
- V3 簽名在簽名塊中又增加了新塊(attr),由更小的 level 塊,以連結串列的形式儲存多個證照。
- 在 V3 方案中,最舊的證照為新塊連結串列的根節點,以此對新證照籤名,確保新證照正確有效。
V3 方案還沒有正式開放,在最新版的 Build Tools 版本 28.0.3 中的 Apksigner,尚不支援 V3 的 APK 簽名方案。想嚐鮮可以通過原始碼自行編譯。
從現有的資料來看,我比較關心的多渠道打包的支援方案,在升級到 V3 之後,舊的 V2 支援的多渠道方案應該依然有效(或者少量改動)。
期待上線後的具體效果。
你對 V3 簽名有什麼想法或者疑問,歡迎在留言區討論。如若本文對你有所幫助,歡迎留言、轉發、點贊。
reference:
Android APK signature scheme V3
公眾號後臺回覆成長『成長』,將會得到我準備的學習資料,也能回覆『加群』,一起學習進步;你還能回覆『提問』,向我發起提問。
