Hi,你們好,我是承香墨影!html
當咱們須要發佈一款 App 到應用市場的時候,通常須要咱們針對不一樣的市場生產不一樣的渠道包,它們使用的是同一套代碼,只是會包含一些各自的渠道信息,用於咱們作數據分析。android
前幾天,企鵝電競團隊開源了本身的 Android Apk 多渠道打包工具:VasDolly,比美團的 Walle 更全面一些。git
正好借這個機會,來說解一下 Android 的不一樣版本的簽名機制的差別。github
經過對 Apk 進行簽名,開發者能夠證實對 Apk 的全部權和控制權,可用於安裝和更新其應用。而在 Android 設備上的安裝 Apk ,若是是一個沒有被簽名的 Apk,則會被拒絕安裝。c#
在安裝 Apk 的時候,軟件包管理器也會驗證 Apk 是否已經被正確簽名,而且經過簽名證書和數據摘要驗證是否合法沒有被篡改。只有確認安全無篡改的狀況下,才容許安裝在設備上。安全
簡單來講,APK 的簽名主要做用有兩個:markdown
而在 Android 中,支持兩種應用簽名的方案:數據結構
既然簽名方案在升級,v1 方案必定有一些缺陷的地方,接下來咱們先來了解一下這兩個方案的細節。工具
v1 簽名方案,並不會保護 Apk 內的全部內容,有一些例外部分,被修改也並不會致使簽名失效。例如:ZIP 元數據。oop
這樣,在驗證 APK 簽名的時候,就須要處理大量不可信(還沒有通過驗證)的數據結構,而後還須要過濾並捨棄掉這部分不受簽名保護的數據,再進行簽名校驗。也就是說你能夠在已簽名的文件中,增長一些不被簽名保護的內容,這將致使受攻擊的可能增大。
另外,v1 方案是對 APK 內部的被保護的原始文件(未壓縮),單獨進行計算數據摘要,因此在驗證期間,也須要對每一個文件進行減壓再進行簽名校驗,來驗證是否被篡改。因此在驗證 APK 簽名的時候,必須解壓 APK 的全部已壓縮的文件條目進行數據摘要的校驗,而這些,都將須要花費更多的時間和內存。
正是由於 v1 方案的缺陷,Android 7.0 開始,才引入了 APK 簽名方案 v2。
APK 簽名方案 v2 是一種全文件的簽名方案,該方案可以對 APK 全部受保護的部分進行簽名保護,從能可以發現它們被篡改。
在 APK 驗證期間,v2 方案會將 APK 文件視爲 Blob,並對整個文件進行簽名檢查。對 APK 進行的任何修改(包括對 ZIP 元數據的修改),都會使 APK 簽名做廢。
使用 APK 簽名方案 v2 進行簽名時,會在 APK 文件中,插入一個 APK 簽名塊,該分塊位於「ZIP 中央目錄」部分以前並緊鄰該部分。在「APK 簽名分塊」內,v2 簽名和簽名者身份信息會存儲在 APK 簽名方案 v2 分塊中。
該分塊包含多個 "ID-值" 對,所採用的封裝方式有助於更輕鬆地在 APK 中找到該分塊。APK 的 v2 簽名會存儲爲一個 "ID-值" 對,其中 ID 爲 0x7109871a。
上圖是簽名先後,APK 文件結構的對比。能夠看到在 v2 已簽名的 APK 中,包含了 4 個部分。
APK 簽名方案 v2 負責保護第 一、三、4 部分的完整性,以及第 2 部分包含的 APK 簽名方案 v2 分塊中的 signed data
分塊的完整性。
第 一、3 和 4 部分的完整性經過其內容的一個或多個摘要來保護,這些摘要存儲在 signed data
分塊中,而這些分塊則經過一個或多個簽名來保護。
第 一、3 和 4 部分的摘要信息,採用一種相似兩級 Merkle 樹的方式進行計算,因此效率上會提升不少。這個就比較複雜了,你們有興趣再深刻研究。
既然已經有了 v2 方案,咱們是否能夠徹底捨棄 v1 方案,只使用 v2 方案呢?
從官方文檔瞭解到,由於 APK 簽名方案 v2 是在 Android 7.0 中引入的,爲了使 APK 能夠在 Android 6.0 以及更低的版本中正常安裝,應該先使用 JAR簽名(v1 簽名)對 APK 進行簽名而後再使用 v2 方案對其進行簽名。
而在實際測試中,這種僅使用 v2 方案不使用 v1 方案的狀況,是能夠編譯經過的,而且在 Android 7.0 之上的設備上也是能夠安裝和運行,可是在 7.0 之下,由於不檢測 v2 簽名,而 APK 又不存在 v1 簽名,在安裝的時候,會提示沒有簽名的錯誤。
爲了保證兼容性的問題,在 7.0 以上的設備中,也是兼容了 v1 簽名的方案。因此 v2 簽名方案,暫時並非一個強制的方案。
優先級是:優先校驗 v2 方案,沒有或者不存在校驗機制,則校驗 v1 方案。
到這裏,我想應該對 v1 和 v2 簽名方案應該已經有必定了解了。v2 簽名既然是升級版,就是爲了解決 v1 簽名方案的一些問題。
一、效率問題
v1 方案,會在 /META-INF/MANIFEST.MF
文件中,記錄全部須要校驗簽名的文件的數據摘要,而且這裏生產數據摘要是依據壓縮前的源文件,而在打包的過程當中,這些文件又會被壓縮。
因此在驗證簽名的過程當中,須要先解壓出原始文件,才能計算數據摘要從而驗證它,而這個過程,會消耗更多的時間和內存。
v2 簽名方案,是對 APK 文件自己進行數據摘要計算,也就是說它只計算一個文件(v1 會計算 Apk 內的不少文件),這樣就不存在解壓 APK 的操做,效率和內存都獲得優化。
二、安全問題
v1 方案,它只會對 APK 內部,部分文件進行校驗,並不會對 APK 的完整性進行校驗。所以,簽名後,咱們依然能夠修改 APK 文件,例如:美團的多渠道方案就是在 /META-INF/
目錄下,添加一個空文件,使用文件名來標誌渠道。
而 v2 簽名是針對整個 APK 進行校驗,因此對 APK 的任何改動,都沒法經過 v2 簽名的驗證,這樣安全性會更高。
關於簽名校驗的耗時上,主要影響的是安裝耗時,這裏有一份實驗室數據(Nexus 6P、Android 7.1.1)可供參考。
差很少 2.x 倍的差距,v2 簽名對 APK 的安裝仍是有很多提高的。
多渠道的需求點,在於同一個 App,須要有一些不一樣來區分它們,最多見的場景就是 Android 國內的市場,對不一樣的市場使用不一樣的渠道包,它們的代碼是一致的,只是一個渠道號的數據不同。這樣區分的好處在於數據更清晰,咱們知道那個渠道的用戶是優質用戶。
既然簽名方案在升級,多渠道的方案也須要升級。曾經有一寫可行的方案,基本上已經被廢棄了。例如:Gradle Plugin 配置不一樣的 Flavors、利用 ApkTool 解包改數據再從新打包並從新簽名。
這些方案都有一些侷限性。例如 Gradle Flavors 方案,每一個渠道都須要從新打包,很是的耗時,而且生成的渠道包 DEX 的 CRC 值都不一致,不利於咱們使用熱更新的方案;而 ApkTool 的方案,首先 解包→打包→從新簽名 的過程一樣耗時,其次在於,不穩定,可能升級了 Gradle Plugin 的版本以後,會致使解包失敗。
因此咱們在想,一個高效的多渠道打包方案,有幾個關鍵單須要注意。
不破壞簽名就限制了不能解包以及從新簽名,勢必對效率有所提升。
而除了 VasDolly 以外,市面上流傳比較廣的就是 美團 給出的 Walle 方案,這裏就以它們的原理進行簡單的講解。
v1 下對簽名的校驗比較弱了,美團給出了完整的解決方案。前面也介紹過,就是在以及打包簽名好的 Apk 中,向 /META-INF
目錄下,寫入一個空文件,以文件名來標識渠道號。
首先,使用這樣的方案,並不會破壞 v1 簽名,因此效率會很高。
而在騰訊的 VasDolly 中,實際上是向 Apk 文件的 EOCD 部分,增長渠道的信息。
APK 文件本質上是一個 ZIP 包,而 EOCD 就是上圖所示的第三部分,而且這部分是不被 v1 簽名校驗的,能夠用來記錄咱們的渠道信息。
v2 方案下,其實騰訊 VasDolly 和美團的 Walle 方案,並無什麼區別,由於驗證更強了,你們可操做的區域就只有那麼多了。
前面也提到過,使用 v2 簽名後的 APK 文件結構中,插入了一個 APK Signing Block 的簽名塊。
在這個 APK 文件結構下,只有 塊2 ,也就是記錄 APK v2 簽名信息的區域,不是所有參與 v2 簽名的校驗,因此你們都在這部分作文章。
APK Signing Block 中包含了多個 "ID-值" 的鍵值對,而 v2 簽名的信息,會記錄在 ID 爲 0x7109871a
中,而不會校驗其餘 ID 下的值。
所以,基於 v2 簽名的多渠道方案就這樣誕生了:在 APK 簽名塊中添加一個額外的 ID-值,用於記錄渠道信息。
在 VasDolly 開源以前,市面上支持 v2 簽名的多渠道打包方案,就屬美團的 Walle 了,下面簡單比對一下它們的優缺點。
具體你想使用哪一種方案,就看你的實際須要了。
美團 Walle Github 地址:
https://github.com/Meituan-Dianping/walle
Walle 掃碼直達
騰訊 VasDolly Github 地址:
https://github.com/Tencent/VasDolly/
VasDolly 掃碼直達
部分圖片來源以及參考資料:
https://source.android.com/security/apksigning/v2
https://github.com/Tencent/VasDolly/wiki/VasDolly%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86
https://tech.meituan.com/mt-apk-packaging.html
今天在公衆號後臺回覆成長『成長』,將會獲得我整理的一些學習資料,也能回覆『加羣』,一塊兒學習進步。
推薦閱讀: