首頁>科技>

文章轉自:開源中國

iOS簽名型別有Development、AD-Hoc、In-House與App Store,而打包過程中又涉及到各種證書、Provision Profile、entitlements、CertificateSigningRequest、p12、AppID......各種概念一大堆,本文將從打包簽名的原理說起,並梳理完全簽名的整體流程,最後講解重簽名的實現以及簽名機制中有哪些需要注意防護的要點。

為了保證App的分發平臺是可控的,以及保證所有安裝到iOS裝置上的App都是經過蘋果官方允許的,蘋果建立了iOS簽名打包機制。要了解iOS簽名機制的實現,我們首先從簽名機制的原理說起。

1. 簽名原理1.1 不對稱加密

網路資料的傳輸可以使用對稱加密以及不對稱加密的方式進行安全防護,對稱加密是指資料傳送者(A)和接收者(B)雙方進行加解密的金鑰是一致的,但這樣會增加金鑰自身分發的不安全性:比如要如何保證金鑰在傳遞過程中不被洩露。

而不對稱加密則由A、B持有一對公私鑰進行加解密,公私鑰鑰匙是成對出現的。對於一個私鑰,有且只有一個與其對應的公鑰,私鑰保密、公鑰公開,但是不能通過公鑰推匯出私鑰,使用私鑰加密的檔案可用公鑰解密,反過來公鑰加密的檔案也只能用私鑰進行解密。加密過程如下:

1.2 資料簽名

這裡主要解決了兩個問題,一個是加密資料大小的問題,另一個是如何驗證公鑰的有效性。

1.2.1 資訊摘要

前面已經講到,iOS打包安裝的過程中會對ipa包進行加解密驗證。然而ipa安裝包大小動輒就有十幾M,大的有好幾G,那如果對這麼大的資料量進行加解密,肯定效率是非常低的。而資訊摘要則是解決了加密資料過大的問題,其原理是對資訊內容通過一個很難被逆向推導的公式計算得到一段雜湊數值,它具有以下特點:

計算得到的雜湊值大小固定,不受原本資訊內容大小的影響;不可逆,根據雜湊值無法推斷得到原本資訊(實際上MD5以及SHA-1演算法已經被證明可以被破解);唯一性,原本資訊內容一致,那麼雜湊值也一致;原資料不同,也不會存在重複的雜湊結果。

使用資訊摘要技術在資料加密傳輸時,傳送方先對檔案內容使用雜湊演算法進行資訊摘要計算,再對摘要內容進行加密,之後將檔案內容以及摘要內容(已加密)傳送出去。

接收方收到資料後,先解密得到摘要內容,再依據相同的雜湊演算法對檔案內容進行資訊摘要計算,最後匹配接收到的雜湊值與計算得到的雜湊值是否一致,如果一致那就說明傳輸過程是安全的。

這樣也就避免了對整體原資料加解密的計算過程,從而提高了驗證效率。

1.2.2 簽名證書

不對稱加密中的公鑰是公開的,誰都可以得到,這樣也就存在了不安全性。比如主動攻擊者C冒充資料傳送者A,將自己偽裝後的公鑰分發給資料接收者B,從而達到監聽A、B之間通訊的目的,又或者是對A、B之間的通訊資料進行注入攻擊。

那為了保證獲取公鑰的安全性,這裡引入CA認證(Certificate Authority)。CA是證明公鑰合法性的權威機構(Apple就屬於CA認證機構),它為每個使用公開金鑰的使用者發放一個數字證書,數字證書的作用是證明證書中列出的使用者合法擁有證書中列出的公開金鑰。使用者使用CA的公鑰對數字證書上的簽名進行驗證,如果驗證通過,也就認為證書內包含的公鑰是有效的。

CA認證確保了使用者公鑰使用過程中的安全性,iOS打包需要向蘋果開發者中心上傳.certSigningRequest檔案,然後配置得到各種.cer證書,這些流程中便包括了開發者向Apple CA認證中心註冊公鑰的過程。

2. iOS簽名2.1 概念要點.certSigningRequest 檔案。從Mac的鑰匙串訪問中生成.certSigningRequest檔案,這個過程會從Mac終端生成一對鑰匙對,私鑰儲存在Mac中,公鑰則包含在.certSigningRequest中。再將.certSigningRequest檔案上傳到Apple後臺即蘋果開發者中心,則可以對應生成開發證書或者釋出證書(.cer檔案)。.cer 檔案:Apple後臺使用Apple私鑰對Mac公鑰進行簽名後生成的證書。.p12 檔案:Mac本地生成的鑰匙對私鑰。由於私鑰是本地私有的,但你可以使用.p12將私鑰匯出給其他團隊成員使用。Identifiers。Identifiers是iOS裝置安裝應用時用來識別不同App的唯一標識,點選建立App IDs,同時勾選app所包含的許可權:APNs、HealthKit、iCloud等。entitlements。App使用到的各種許可權(APNs、HealthKit、iCloud等),也是需要Apple驗證通過後才能生效的,Apple將這些許可權開關統一稱為Entitlements。當第一次在Xcode中勾選許可權時,專案中會自動生成一個.entitlements字尾的檔案,裡面記錄了App所擁有的許可權。Profiles。.cer檔案只是聲明了證書的型別,比如Apple Development、Apple Distribution、APNs推送等等,而至於使用什麼證書打包、AppID是什麼、打包的App包含了哪些功能、可以在哪些裝置上安裝,則是通過Provisioning Profile 描述檔案(.mobileprovision字尾)來說明的,蘋果後臺將所有這些資訊組合後再使用Apple私鑰進行簽名,最後生成Provisioning Profile描述檔案:2.2 AppStore簽名

釋出App至AppStore之前需要經過蘋果後臺稽核,稽核通過蘋果後臺會用Apple私鑰對App資料進行加密簽名生成ipa包;使用者從AppStore下載App後,使用裝置內建的Apple公鑰解密驗證,驗證通過安裝成功。由於AppStore分發的過程中上傳稽核、下載安裝的整個過程都處在蘋果的生態鏈內,所以只需要一次驗證就能保證安全性。

2.3 其他簽名

從AppStore下載安裝App只需要一次數字簽名就足以保證安全性,但除了這種途徑蘋果還有其他的安裝方式:

開發中連線裝置到Xcode進行除錯安裝AD-Hoc內部測試安裝,需要先獲取裝置UDID並註冊,並且有最多100臺裝置的限制In-House企業內部分發,安裝裝置數量無限制,但安裝後需主動在設定中選擇信任證書

那這些安裝App的過程中蘋果又是怎樣保證流程安全性的呢?答案就是雙重簽名機制,蘋果使用前面講到的Mac本地鑰匙對以及Apple後臺鑰匙對進行多次數字簽名,從而保證整體流程的可控。

Mac 鑰匙串訪問 在本地生成一對公私鑰鑰匙對,下面預設為公鑰L、私鑰L(L:Local)。Apple已有一對公私鑰鑰匙對,私鑰A在Apple後臺,公鑰A內建到每一臺iOS裝置終端(A:Apple)。上傳公鑰L至Apple後臺,使用私鑰L對公鑰L進行數字簽名生成簽名證書.cer,同時使用私鑰L對額外資訊(使用什麼證書打包、AppID、打包的App包含了哪些功能、可以在哪些裝置上安裝)進行簽名生成描述檔案Provisioning Profile,之後將.cer和Provisioning Profile下載安裝到Mac機器上。編譯打包app,選擇簽名證書.cer,打包指令會自動找到該證書對應的私鑰L(能匹配是因為鑰匙對是成對出現的,前提是本地必須已經存在L私鑰,也就是p12的安裝),然後使用私鑰L對app進行簽名。這些簽名資料包含兩部分:Mach-O可執行檔案會把簽名直接寫入這個檔案中,其他資原始檔則會儲存在_CodeSignature目錄下。你可以將打包生成的.ipa檔案另存為.zip,解壓後對Payload資料夾中的.app檔案右鍵、顯示包內容,就可以看到簽名資料。另外簽名過程中對於App內包含的動態庫以及外掛(Plugins、Watch、Frameworks資料夾),每一個都會單獨進行一次簽名,並生成各自的Mach-O可執行檔案和_CodeSignature。簽名資料指程式碼內容、App包含的所有資原始檔,只要其中有任何改動,都必須重新簽名才有效。打包的過程中會將描述檔案Provisioning Profile命名為embedded.mobileprovision放入到打包app中。安裝/啟動,iOS裝置使用內建的公鑰A驗證embedded.mobileprovision是否有效(裝置是否在允許安裝列表內),同時再次驗證裡面包含的.cer證書籤名是否有效(證書過期與否)並取出公鑰L。embedded.mobileprovision驗證通過,就使用公鑰L解密驗證app簽名信息:AppID是否對應、許可權開關是否跟app裡的entitlements一致等等。所有驗證通過,安裝/啟動完成。

以上流程便是開發除錯、AD-Hoc、In-House等方式打包安裝App的過程,區別只在於第⑤步中裝置IDs的匹配規則不一致。開發除錯只安裝當前聯調的裝置;AD-Hoc允許安裝到已在開發者賬號下注冊過的裝置,且每年最多允許100臺;In-House無裝置數量限制,常用於企業內部App的分發。

3. ipa包重簽名

ipa包重簽名主要針對的是非App Store的安裝包,App Store分發最終是上傳ipa檔案到蘋果後臺稽核,通過後使用Apple私鑰加密,然後才能釋出安裝,不存在重簽入侵的可能。而開發除錯、AD-Hoc、In-House等分發途徑生成的ipa包不存在蘋果後臺驗證的步驟,這也就意味著你可以對任意的.app、 .ipa檔案進行重簽名。

回顧前面講到的簽名流程,真正對ipa包進行簽名的關鍵步驟(④⑤)是在Mac本地進行的,簽名過程中需要滿足三個條件:App即軟體程式碼編譯生成的產物、p12證書以及Provisioning Profile配置檔案。其中App的內容是動態變動的,Apple不會去驗證它,實際上也無需驗證,因為在開發除錯過程中,所開發的App肯定是不停的迭代變化的,如果需要上線App Store那Apple只需在稽核階段對App內容進行把關驗證即可,而其他分發渠道它則管不了。p12以及Provisioning Profile則是下載後主動安裝的,大部分情況下都是由管理員建立下載好之後,匯出分發給團隊成員。

3.1 簽名指令

iOS簽名呼叫的是codesign指令,你也可以直接使用相關指令進行簽名,下面是codesign的常用指令:

# MAC終端輸入: codesign --helpcodesign --helpUsage: codesign -s identity [-fv*] [-o flags] [-r reqs] [-i ident] path ... # signcodesign -v [-v*] [-R=<req string>|-R <req file path>] path|[+]pid ... # verifycodesign -d [options] path ... # display contentscodesign -h pid ... # display hosting paths

檢視Xcode的編譯日誌,也可以看到簽名的詳細資訊

# 簽名指令codesign -f -s "iPhone Distribution: XXX(證書名稱)" --entitlements entitlements.plist(Profile配置檔案) XXX.app(簽名app)3.2 重簽名首先獲取需要重簽名的ipa包,注意該ipa包必須是未加密的。如果是從App Store下載的ipa,需要砸殼解密後才能進行重簽名,你也可以從越獄平臺下載。將獲取的.ipa重新命名為.zip,然後右鍵解壓,將會生成一個 Payload 資料夾,裡面包含.app檔案。將簽名證書對應的Provisioning Profile檔案重新命名為 embedded.mobileprovision,並拷貝放到Payload資料夾中。同時右鍵.app檔案,顯示包內容,將前面的embedded.mobileprovision檔案再拷貝一份放到.app資料夾中,替換掉原有的embedded.mobileprovision。entitlements.plist是由簽名證書對應的Profile配置匯出的簽名檔案,它與前面截圖Xcode簽名日誌中的XXX.xcent檔案的作用相同。終端cd到Payload資料夾路徑,執行指令# cd xxx/Payload,然後執行下面指令 security cms -D -i embedded.mobileprovision將會打印出Profile配置的內容,找到<key>Entitlements</key>,然後把<key>Entitlements</key>下面<dict>...</dict>的內容拷貝到新建的entitlements.plist檔案中(可以通過Xcode生成plist檔案,選Property List型別),最後將entitlements.plist檔案放到Payload資料夾中。# 拷貝內容為:<dict> ... </dict> <key>Entitlements</key> <dict> <key>application-identifier</key> <string>xxx</string> <key>keychain-access-groups</key> <array> <string>xxx</string> </array> <key>get-task-allow</key> <false/> <key>com.apple.developer.team-identifier</key> <string>xxx</string> </dict> 簽名證書名稱可以在安裝證書後從鑰匙串中心檢視或者在終端使用以下指令檢視:security find-identity -v -p codesigning準備工作完成,開始重簽名。先右鍵.app顯示包內容,檢視動態庫和外掛(Plugins、Watch、Frameworks資料夾),如果是個人證書需要移除Plugins、Watch資料夾,因為個人證書沒法簽名Extention。如果存在Frameworks,則執行簽名指令,有多個的話則每一個Frameworks都要重籤一次。codesign -fs "簽名證書名稱" "Frameworks/xxx.framework(動態庫路徑)"最後對app進行重簽名codesign -f -s "iPhone Distribution: XXX(證書名稱)" --entitlements entitlements.plist(Profile配置檔案) XXX.app(簽名app)最後將Payload資料夾下的資源移除,只保留.app檔案,右鍵壓縮,然後更改字尾為.ipa,這樣重籤後的ipa便已生成了,你可以通過iTunes、iTools或其他途徑安裝到iOS裝置上。3.3 注入程式碼重籤ipa程式碼注入一般通過動態庫來實現。新建動態庫在Xcode中選擇新建 TARTETS — Framework & Library — Framework,然後在framework中新增自定義程式碼,一般都是使用Runtime來注入附加功能。最後選擇framework要支援的架構,編譯後便得到了最終動態庫。對需要重簽名的.app右鍵顯示包內容,然後將動態庫拷貝到Framework資料夾(沒有則新建)中。然而此時動態庫與app還沒建立關聯關係,動態庫需要注入MachO中才能生效。注入使用yololib工具,下載yololib並編譯,將生產的命令複製到/usr/local/bin或$PATH中的其他路徑,便可以在終端使用yololib指令## 通過yololib工具實現注入動態庫 yololib "MachO檔案路徑" "需要注入的動態庫路徑"注入成功後再對所有Framework簽名,最後對app重簽名,然後生成ipa檔案。這裡整理了一份用於重簽名的指令碼 CJCodeSign,想了解更多關於簽名指令的內容可點選檢視詳情。3.4 關於重簽名的思考

iOS重簽名實現,可以發現用於簽名的私鑰資源(包括.cer證書和Provisioning Profile配置)和實際簽名的app包是沒有強關聯關係的,這也就帶來了兩方面的問題。

.cer證書和Provisioning Profile配置被用於其他App的分發簽名,特別如果是In-House企業型別的證書,那是可以進行無限制分發的,而一旦蘋果檢測到這種違規簽名的行為,輕則撤銷證書,重則登出企業開發者賬號!這也就是為什麼一定要嚴格把控 p12、Provisioning Profile 檔案外發的原因。自有App被注入程式碼後重簽名,比如應用多開、新增外掛、惡意抓包等等,對於這一類的防護除了對Bundle ID進行檢查,以及對App動態庫增加白名單檢索外好像也沒有更好的辦法。當然這已經涉及到逆向防護的方向了,本人對此還未深入了解,有興趣的同學可以一起參與探討。

全文完!

最後再附上重簽名指令碼地址: CJCodeSign

作者簡介:

lele8446,iOS開發深耕者,愛好分享、深⼊探討有溫度的內容,GitHub地址。

  • 整治雙十一購物亂象,國家再次出手!該跟這些套路說再見了
  • 分析師:新冠病毒疫情不影響蘋果5G iPhone的釋出