1、簽名是什麼
要知道簽名是什麼,先來看爲什麼需要簽名 。大家都知道,在消息通信時,必須至少解決兩個問題:一是確保消息來源的真實性,二是確保消息不會被第三方篡改。在安裝Apk時,同樣需要確保Apk來源的真實性,以及Apk沒有被第三方篡改。如何解決這兩個問題呢?方法就是開發者對Apk進行簽名:在Apk中寫入一個“指紋”。指紋寫入以後,Apk中有任何修改,都會導致這個指紋無效,系統在安裝Apk進行簽名校驗時就會不通過,從而保證了安全性。進行簽名校驗,校驗通過後才能安裝成功。那在這個過程中籤名校驗的機制是什麼?具體校驗的是什麼內容?我們APP是如何進行簽名管理、簽名以及發佈驗證呢?本篇文章將從這幾個方面進行介紹。
要了解如何實現簽名,需要了解兩個基本概念:數字摘要和數字證書。
1.1數字摘要
數字摘要是將任意長度的消息變成固定長度的短消息,它類似於一個自變量是消息的函數,也就是Hash函數。數字摘要就是採用單向Hash函數將需要加密的明文“摘要”成一串固定長度的密文,這一串密文又稱爲數字指紋,它有固定的長度,而且不同的明文摘要成密文,其結果總是不同的,而同樣的明文其摘要必定一致。
1.2簽名大概過程
前面已經說到,可以通過簽名來確保數據來源的可靠性和數據的不可篡改性。簽名就是在摘要的基礎上再進行一次加密,對摘要加密後的數據就可以當作數字簽名,在安裝Apk需要對簽名進行驗證,驗證通過才能繼續安裝。
1.3證書
接收方必須要知道發送方的公鑰和所使用的算法。如果數字簽名和公鑰一起被篡改,接收方無法得知,還是會校驗通過。如何保證公鑰的可靠性呢?答案是數字證書,系統在安裝Apk時並沒有校驗證書本身的合法性,只是從證書中提取公鑰和加密算法,這也正是對第三方Apk重新簽名後,還能夠繼續在沒有安裝這個Apk的系統中繼續安裝的原因。
2.簽名校驗
Android與iOS簽名實現和校驗方式有所不同,以下將分平臺介紹兩端各自簽名校驗過程。
2.1Android簽名方式
Android 的簽名方案,發展到現在,已經支持三種應用簽名方案:
- v1 方案:基於 JAR 簽名。
- v2 方案:APK 簽名方案v2,在 Android 7.0 引入。
- v3 方案:APK 簽名方案v3,在 Android 9.0 引入。
目前我們APP大多采用V1+V2簽名方式,由於V2方式不支持低於7.0的版本,因此,爲了低版本正常安裝,先使用v1簽名再使用v2簽名。在實際應用中,優先校驗v2簽名,沒有或不存在校驗機制時,校驗v1簽名。在主工程build.gradle中定義了簽名配置。
2.1.1V1簽名
其中由於V1簽名生成的文件是META-INF中MAINIFEST.MF CERT.RSA CERT.SF,那這三個文件之間是如何對APK進行簽名的呢,一張圖足以說明整個簽名過程:
根據上面簽名過程,V1簽名校驗流程具體是:
- 首先校驗cert.sf文件的簽名
計算cert.sf文件的摘要,與通過簽名者公鑰解密簽名得到的摘要進行對比,如果一致則進入下一步;
- 校驗manifest.mf文件的完整性
計算manifest.mf文件的摘要,與cert.sf主屬性中記錄的摘要進行對比,如一致則逐一校驗mf文件各個條目的完整性;
- 校驗apk中每個文件的完整性
逐一計算apk中每個文件(META-INF目錄除外)的摘要,與mf中的記錄進行對比,如全部一致,剛校驗通過;
- 校驗簽名的一致性
如果是升級安裝,還需校驗證書籤名是否與已安裝app一致。
在校驗步驟中,任何一步校驗出錯,都會導致APP簽名校驗不通過,無法安裝APP或無法覆蓋安裝,例如:
- 如果篡改apk內容,會導致校驗apk每個文件完整性失敗,因爲此文件hash值會被更改,與.mf和.sf中不同;
- 如果篡改apk內容,同時篡改.mf以及.sf摘要信息,在校驗.sf簽名是也會失敗;
- 如果將apk內容和簽名信息一同篡改,相當於對apk進行重新簽名,他會相當於一個新APP安裝到系統中,無法進行覆蓋安裝。
2.1.2V2簽名
通過V1簽名我們可以知道,V1簽名是在apk文件中增加META-INF目錄,而V2簽名是全文件簽名方式,可以對.apk所有受保護的內容進行簽名保護。APK文件結構上來看,由3個部分構成:ZIP 條目的內容、ZIP 中央目錄、ZIP 中央目錄結尾。V2方案爲加強數據完整性保證,不在ZIP 條目的內容和ZIP 中央目錄中插入數據,選擇在兩者之間插入一個APK簽名分塊,從而保證了原始zip(apk)數據的完整性。
第1、3、4部分的完整性是通過內容摘要來保護的,這些摘要保存在signed data分塊中,而signed data分塊的完整性是通過簽名來保證的。
根據上面簽名方式原理,V2簽名校驗流程具體是:
- 找到APK簽名分塊並驗證以下內容:
APK 簽名分塊的兩個大小字段包含相同的值。
ZIP 中央目錄結尾緊跟在ZIP 中央目錄記錄後面。
ZIP 中央目錄結尾之後沒有任何數據。
- 找到APK 簽名分塊中的第一個APK 簽名方案 v2 分塊。如果 v2 分塊存在,則繼續執行第 3 步。否則,回退至使用 v1 方案驗證 APK。
-
對APK 簽名方案 v2 分塊中的每個signer執行以下操作:
從 signatures 中選擇安全係數最高的受支持 signature algorithm ID。安全係數排序取決於各個實現/平臺版本。
使用公鑰並對照signed data 驗證 signatures 中對應的 signature。
驗證 digests 和 signatures 中的簽名算法 ID 列表(有序列表)是否相同。這是爲了防止刪除/添加簽名。
使用簽名算法所用的同一種摘要算法計算 APK 內容的摘要。
驗證計算出的摘要是否與 digests 中對應的 digest 相同。
驗證 certificates 中第一個 certificate 的 SubjectPublicKeyInfo 是否與公鑰相同。
- 如果找到了至少一個 signer,並且對於每個找到的 signer,第 3 步都取得了成功,APK 驗證將會成功。
2.1.3V1、V2簽名對比
我們APP目前都向支持V2簽名轉變,那爲什麼要支持新的簽名機制呢?根據兩種簽名機制的原理分析,我們不難看出,V2簽名是優於V1簽名,具體對比如圖所示:
簽名方式 | 效率方面 | 安全方面 |
V1簽名 | 低 需對所有文件進行hash校驗,速度較慢 |
不夠安全 只保證了APK內各文件的完整性,APK其它內容的完整性未保證 |
V2簽名 | 高 只需進行一次hash校驗,速度快 |
較安全 除保證了APK內各文件的完整性,APK中數據區、中央目錄和中央目錄結尾記錄的完整性均得到了保證 |
簽名校驗耗時,體現在安裝耗時上,同一部手機,安卓7,安裝同樣的包,v2簽名的apk安裝耗時是v1簽名的1/3 |
2.2iOS簽名方式
iOS採用雙層代碼簽名校驗
生成簽名:
在Mac開發機器生成一對公私鑰,這裏稱公鑰L,私鑰L;
把公鑰L上傳到蘋果後臺,用蘋果後臺裏的私鑰A去簽名公鑰L。得到一份數據包含了公鑰L以及其簽名,把這份數據稱爲證書,和一份描述文件;
編譯完一個 APP 後,用本地的私鑰M對這個APP進行簽名,同時把從蘋果服務器得到的 Provisioning Profile 文件打包進APP裏,文件名爲embedded.mobileprovision。
認證過程:
在安裝時,iOS 系統取得證書,通過系統內置的公鑰 A,去驗證證書的數字簽名是否正確;
通過系統內置的公鑰 A,解密拿到描述文件,查看裏面的設備列表時候包含當前設備;
驗證證書後確保了公鑰 L 是蘋果認證過的,再用公鑰 L 去驗證 APP 的簽名;
驗證描述文件裏的AppID是否與當前App的AppID一致,App申請的功能時候與描述文件一致。
3.簽名管理與發佈驗證
3.1簽名管理
目前android與iOS端證書文件均由RD提供,QA統一嚴格管理。
android證書佈置在打包機器,代碼工程配置使用,打出不同類型包。
iOS證書存放打包機器,在運行打包命令時使用,打出不同類型包。
3.2發佈驗證
目前打包平臺所包含包類型如下:
3.2.1Android端
證書類別 | 特點 | 有效期 | 說明 | 使用場景 |
debug證書 | 不同app使用同一debug證書,但不能覆蓋安裝 | 1年 | 可進行debug調試,debug包未做混淆,不得外傳 | 單元測試,debug調試 |
release證書 | 不同app可能相同release證書 | 根據生成配置 | 調試麻煩,集成時需要驗證代碼混淆是否造成bug | 集成測試,發佈市場 |
使用release包發佈,首先驗證已開啓代碼混淆,另外需要驗證覆蓋安裝,保證證書一致。
3.2.2iOS端
證書類別 | 特點 | 有效期 | 說明 | 使用場景 |
App Development | 可以製作多個副本分發給多臺設備 | 1年 | 只可以使用Xcode進行真機調試 | 本地調試 |
InHouse | 只能有一個,不能製作副本分發到多臺電腦 | 3年 | 可以在任意一臺iOS設備上安裝,肆意的安裝可能會遭到封號 | 單元測試,通過第三方託管發佈內部渠道 |
AdHoc | 非越獄的設備也能夠安裝,該設備的UDID已經添加到開發者賬號所在的組中 | 單元測試,集成測試 | ||
AppStore | 1年 | 可直接提交App Store或在越獄機上使用 | 集成測試,發佈App Store |
使用release或者inhouse包發佈,需要驗證覆蓋安裝,保證證書一致。