App簽名二三事

南華Coder發表於2020-04-05

一、概述

相比於Android系統,iOS對下載到裝置中的軟體有比較嚴格的限制;絕大多數人,只會從AppStore下載App,這也杜絕了很多安全隱患;但是對於iOS開發者來說,需要搞明白很多事情(如:iOS App的簽名原理),甚至需要做一些小動作(如重簽名)來達到自己(友好的)目的。

1、基礎概念

  • 摘要演算法:把一個任意長度的位元組串對映 為一定長度的十六進位制的數字串;這個數字串稱為雜湊值。常見有:MD5、SHA1、SHA256、SHA512等

  • 對稱加密:加密和解密使用相同金鑰,常見有:DES演算法、3DES演算法和AES演算法等;

  • 非對稱加密:加密和解密使用不同金鑰的加密演算法,用公鑰加密的資料,要用私鑰才能解密,用私鑰加密的資料,要用公鑰才能解密;常用加密演算法有:RSA、Elgamal、揹包演算法等;

  • 數字簽名(digital signature):

    • 是非對稱加密與摘要演算法的結合,用於驗證資料的完整性及不可抵賴性;
    • 傳送方對資料計算出摘要資訊,然後用傳送方私鑰加密,得到摘要密文,這就是數字簽名;
    • 接收方收到後,利用傳送方的公鑰和非對稱演算法從數字簽名中獲取摘要明文;根據原始內容計算出摘要 和 解密出來的摘要明文進行對比;不一致,說明內容被篡改 or 收到內容不是指定傳送方;
  • 數字證書(digital certificate):

    • 數字證書數為了保護髮送方公鑰不被偽造而發明的,引入證書中心(Certificate Authority,CA)概念,CA用自己的私鑰,對傳送方的公鑰和一些相關資訊一起加密,生成"數字證書"(Digital Certificate)。
    • CA的數字證書中有:簽發者、證書用途、傳送方公鑰、傳送方非對稱加密演算法、傳送方HASH演算法和到期時間等
    • 接收方拿到數字證書後,先從數字證書中解密出傳送方公鑰(用的是CA的公鑰和CA解密演算法);然後根據傳送方公鑰去解密數字證書,得到摘要;最後比對原始資料計算出的摘要是否一致。
    • CA是第三方機構,CA公鑰是公開的,接收方可以跟別人比對(比如網上查),因此不可能偽造。而傳送方公鑰,是接收方從數字證書中獲得的。
    • 數字證書在https協議實現中有重要應用

2、簽名相關的幾個概念

名稱 作用
證書(cer) 內容是公鑰或私鑰,由其他機構對其簽名組成的資料包。
Entitlements 包含了 App 許可權開關列表
CertificateSigningRequest 本地公鑰
p12 本地私鑰,可以匯入到其他電腦。
Provisioning Profile 包含了 證書 / Entitlements 等資料,並由蘋果後臺私鑰簽名的資料包。

3、iOS包渠道及其簽名機制

  • iOS裝置上App的渠道粗分有AppStore渠道非AppStore渠道,非AppStore包有:Testflight內測包、In-House 企業內部分發包、Ad-Hoc(相當於企業分發的限制版,限制安裝裝置梳理)和Xcode除錯安裝;(越獄包不在此範圍)。

  • AppleStore中渠道包簽名驗證

    • 蘋果官方生成一對公私鑰,在 iOS 系統中內建一個公鑰,私鑰由蘋果後臺儲存。
    • App 上傳到 App Store 時,蘋果後臺用私鑰對 App 資料進行簽名(計算出摘要,再私鑰加密);
    • iOS 下載這個 App 後,用公鑰驗證這個簽名,如果簽名正確則這個 App 肯定是由蘋果後臺認證的,並且沒有被修改或損壞。
  • 非AppleStore渠道包的簽名驗證需要使用雙重簽名機制,保證不被濫用。

二、雙重簽名機制

1、簡介

  • 使用兩對公私鑰做加密驗證,分別是 Mac本地的一對公私鑰Apple提供的一對公私鑰(私鑰在蘋果後臺,公鑰在每個 iOS 裝置上)。
  • 雙重簽名的存在是為了滿足:
    • App 需要經過蘋果允許才能安裝;
    • 在 Apple 後臺中註冊過的裝置才能安裝,比如在 TestFlight 內測、真機除錯模式下;
    • 限制簽名只能對應唯一的 App;

2、重要概念

  • Mac 上執行鑰匙串訪問 -> 證書助理 -> 從證書頒發機構請求證書...,就會在Mac本地生成了一對公私鑰,匯出的 CSR 檔案(CertificateSigningRequest.certSigningRequest)就是 Mac 公;

  • CSR 檔案上傳到蘋果後臺,蘋果用Apple私鑰對其簽名,並生成一份包含Mac公鑰資訊 和 蘋果簽名資訊的開發/釋出證書cer

  • 當我們將cer下載並安裝到Mac後,keychain會把CertificateSigningRequest和cer證書關聯起來。在鑰匙串中找到該證書,可以匯出Mac私鑰(.p12 檔案)

  • 在蘋果後臺需要配置AppID、可用裝置IDs(企業證書不需要) 和 Entitlements(App 許可權開關列表),對這些額外資訊 和 cer證書使用Apple私鑰簽名,最後蘋果將證書 + 額外資訊 + 簽名組成一個Provisioning Profile檔案(字尾mobileprovision),可下載到Mac上。

    Provisioning Profile檔案又被成為描述檔案,安裝好後,存放在~/Library/MobileDevice/Provisioning Profiles路徑下
    複製程式碼

3、App簽名和驗證

雙簽名和驗證

  • 在Mac上編譯完一個App後,Mac先用Mac私鑰對App簽名,並將Provisioning Profile檔案也打包到App中,檔名為embedded.mobileprovision

  • iOS系統安裝App時,蘋果通過內建在手機中的Apple公鑰驗證embedded.mobileprovision中的簽名是否正確,接著驗證證書中的簽名是否正確

  • 在確保embedded.mobileprovision裡的資料都是蘋果授權以後,就從裡面取出資料,做後續各種驗證,包括

    • 用Mac公鑰驗證App簽名
    • 驗證裝置 ID 是否在 ID 列表上
    • 驗證證書是否過期
    • 驗證AppID 是否對應得上
    • 驗證許可權開關是否跟 APP 裡的 Entitlements 對應等等。
  • 如果別的 Mac 也要編譯後簽名這個 App,就必須要獲取申請生成cer證書那個Mac機器上的私鑰;這個比較簡單,只需要在那臺機器的鑰匙串中找到cer證書,然後右鍵匯出Mac私鑰(.p12 檔案);

  • 簡單來說,要在別人裝置上成功編譯成功並將App安裝到裝置中,需要cer證書匯出的**.p12檔案和Provisioning Profile檔案**(描述檔案)

4、補充

  • 雙層程式碼簽名是針對開發測試包、In-House 企業簽名、Ad-Hoc 包為例的簽名和驗證的流程,只是企業簽名不限制安裝的裝置數,因此描述檔案中不會有裝置列表,而是一條 ProvisionsAllDevices 記錄。
  • 從 App Store 上下載的安裝包,裡面是沒有描述檔案的,但上架之前還是要配置證書、PP 檔案,因為 App ID 和許可權的檢驗還是需要做的。但 App 上傳到 AppStore 以後就跟 PP 檔案沒有關係了,所以我們可以理解為 App Store 上包的簽名驗證採用就是前面說的最簡單的簽名方式,Apple 後臺直接用私鑰簽名 App 就可以了。

三、App重簽名

1、概述

  • 重簽名本質是將已釋出/未釋出的包重新簽名為自己的證書和簽名,關鍵點是替換ipa內的證書描述檔案
  • 使用codesign工具

2、重簽名方案

  • 檢視ipa包是否加殼,只有未加殼的包才可以重簽名。

    otool -l app_name.app/app_name | grep crypt
    
    # 輸出cryptid為0代表已經砸殼,即解密,為1或者2表示以第1類或者第2類加密方案加密。
    複製程式碼
  • 檢視本地證書列表並記錄下要用來簽名的證書名,例如”iPhone Distribution: XXXXX (XXX)”

    security find-identity -v -p codesigning
    # 輸出有效的證書列表
    複製程式碼
  • 建立一個和App同名的工程,從上步得到有效證書列表中,選擇一個,編譯後生成新App;將這個新App裡embedded.mobileprovision檔案取出替換iap包中的檔案。

  • 刪除ipa包內部不能被重簽名的外掛(PlugIns資料夾 和 Watch資料夾)

  • 將ipa包內的所有Framework中Mach-O檔案重簽名(Frameworks目錄下有Framework)

# 命令參考
codesign -fs [證書名稱] [要簽名的檔案]

#如果沒有許可權,執行chmod +x app_name.app/app_name 給Mach-O檔案新增可執行許可權
#Frameworks資料夾裡面的.framework本質還是資料夾,真正要重籤的是.framework裡面的MachO可執行檔案
複製程式碼
  • 將ipa包內info.plist的BundleId修修改為新App對應的的BundleId

  • 用命令檢視embedded.mobileprovision檔案,找到其中的entitlements欄位,並且複製entitlements欄位和其中的內容。

    security cms -D -i 「embedded檔案路徑」
    複製程式碼
  • 新建entitlements.plist檔案,將複製內容拷貝到檔案中,然後將entitlements.plist複製到ipa的同級目錄下。

  • 對App進行重簽名,並壓縮成新的ipa包

    # 重簽名
    $ codesign -fs "iPhone Distribution: XXXXX (XXX)" --no-strict --entitlements=entitlements.plist
    
    // --no-strict 不嚴謹的 
    // --entitlements=entitlements.plist許可權所在檔案是entitlements.plist
    codesign -fs 簽名證書 --no-strict --entitlements=entitlements.plist app_name.app
    
    # 壓縮ipa包
    $ zip -r 「輸出的檔名(.ipa)」 Payload/
    複製程式碼
  • 將ipa包安裝到手機,若能同時存在兩個應用且能正常執行則表示重簽名成功。

3、防止App被重簽名辦法

  • 校驗描述檔案資訊:在啟動時校驗描述檔案資訊與打包時是否一致。例如判斷組織單位: 先記錄證書中的組織單位資訊。
  • sysctl檢測是否被除錯,具體可見iOS安全防護之重簽名防護和sysctl反調

4、目的

  • 對於大多數iOS開發,瞭解App簽名原理,知道要對App做防止重簽名的保護即可。
  • 本人並非從事越獄安全工作;使用重簽名,主要是為了讓測試包可以支援IAP測試,搞過IAP的同學應該明白IAP測試中的痛點: 使用TestFlight or ad-hoc包測試的效率真的會把人逼瘋,企業內測又不支援[坑]

歷史文章

淺談資料加密

淺談程式碼混淆

參考文章

程式碼簽名探析

iOS App 簽名的原理

iOS應用安全3 -- APP重簽名

相關文章