iOS應(yīng)用簽名
何為代碼簽名
代碼簽名,就是對(duì)可執(zhí)行的文件或者腳本進(jìn)行數(shù)字簽名择示。
主要用來(lái)確認(rèn)軟件是否被認(rèn)可束凑,且在簽名后未被修改或者損壞的措施。
與數(shù)字簽名的原理一樣栅盲,只不過簽名的數(shù)據(jù)是代碼而已
簽名流程
通過將源代碼進(jìn)行散列Hash后的Hash值進(jìn)行私鑰M加密并與源代碼一起打包成軟件包汪诉。
在使用端中使用公鑰M進(jìn)行解密得到Hash值,并通過相同的散列Hash對(duì)源代碼進(jìn)行Hash谈秫,將得到的結(jié)果進(jìn)行匹配扒寄,如果一致,說(shuō)明源代碼沒有被篡改過拟烫,且是正版應(yīng)用该编。
蘋果雙層簽名驗(yàn)證原理
首先先分析下Apple應(yīng)用的需求
- 針對(duì)開發(fā)情況安裝包不需要上傳至App Store,就可以直接安裝至手機(jī)上
- Apple為了保證系統(tǒng)的安全性硕淑,又必須對(duì)安裝的App有絕對(duì)的控制權(quán)
- 經(jīng)過Apple允許才能安裝
- 不能被濫用導(dǎo)致非開發(fā)的App也能被安裝
為了實(shí)現(xiàn)這一需求课竣,Apple開始提出了雙層簽名的iOS簽名方式。
雙層簽名邏輯
在Apple服務(wù)器中存在著一個(gè)私鑰A
置媳,而每一部Apple移動(dòng)設(shè)備中存在著公鑰A
于樟。這樣一來(lái)就能確保每個(gè)應(yīng)用都是Apple允許的。
但是拇囊,在開發(fā)階段我們需要頻繁的進(jìn)行App的調(diào)試迂曲,因此Apple新增加了一層簽名,來(lái)解決App安裝到設(shè)備上的安全性寥袭。
而這一層簽名是怎么實(shí)現(xiàn)的呢路捧?
初期
- 通過Mac的鑰匙串訪問生成請(qǐng)求的CSR(Certificate Signing Request)文件
創(chuàng)建CSR文件時(shí)关霸,Mac會(huì)生成一對(duì)公私鑰M
,并將包含有公鑰M
的CSR文件發(fā)送給Apple服務(wù)器鬓长。 - Apple服務(wù)器接收到請(qǐng)求后谒拴,利用
私鑰A
對(duì)公鑰M
進(jìn)行數(shù)字簽名,生成證書涉波。 - 針對(duì)每個(gè)App生成對(duì)應(yīng)對(duì)
描述文件
英上。
這個(gè)描述文件中包含了相應(yīng)的信息和權(quán)限,以及對(duì)應(yīng)的證書(公鑰M
的數(shù)字簽名的) - 開發(fā)初期會(huì)通過Apple服務(wù)器下載相應(yīng)App的
描述文件
啤覆,并與Mac上的私鑰M
進(jìn)行關(guān)聯(lián)苍日。
App編譯安裝
- 通過IDE(Xcode)編譯生成的App中包含了
Mach-O可執(zhí)行文件
、App的簽名
和描述文件
窗声。
App的簽名
就是通過私鑰M進(jìn)行的簽名操作生成的相恃。 - 當(dāng)進(jìn)行App安裝時(shí),手機(jī)上的
公鑰A
會(huì)去驗(yàn)證你的安裝行為是否合法笨觅。
通過公鑰A
去校驗(yàn)證書信息拦耐,如果能夠解密且對(duì)應(yīng)的Hash校驗(yàn)沒有問題的話,說(shuō)明是合法可安裝的见剩,如果無(wú)法解密或者說(shuō)Hash校驗(yàn)有誤則不合法不能安裝杀糯。 - 當(dāng)運(yùn)行時(shí),
公鑰A
解密得到的公鑰M
去驗(yàn)證App的簽名
苍苞,如果合法就能運(yùn)行固翰,反之不允許運(yùn)行。
描述文件
為了解決應(yīng)用濫用的問題羹呵,Apple又添加了兩個(gè)限制
第一 限制在Apple服務(wù)器注冊(cè)過的設(shè)備才能安裝
第二 限制簽名只能針對(duì)某個(gè)具體的App應(yīng)用
- 且Apple還控制著App中的
iCloud
/Push
/后臺(tái)運(yùn)行
等權(quán)限骂际,所以Apple把這些開關(guān)統(tǒng)一稱為Entitlements
(授權(quán)文件),并將這個(gè)文件放到了Provisioning Profile
(描述文件)文件中冈欢。- 描述文件是在AppleDevelop網(wǎng)站上創(chuàng)建的歉铝,Xcode運(yùn)行時(shí)會(huì)打包進(jìn)App內(nèi)。
- 開發(fā)時(shí)凑耻,編譯完一個(gè)App后犯戏,用本地的
私鑰M
對(duì)這個(gè)App進(jìn)行簽名,同時(shí)把系統(tǒng)服務(wù)器獲取到的描述文件
打包進(jìn)App中拳话,文件名為embedded.mobileprovision
,再把App安裝至手機(jī)上讓系統(tǒng)做驗(yàn)證种吸。
App重簽名
codesign重簽名
針對(duì)已砸殼
的ipa包弃衍,我們可以手動(dòng)進(jìn)行重簽名,以便與我們了解其應(yīng)用的內(nèi)部坚俗。
MacOS中镜盯,為我們提供了codesign的終端命令行岸裙,讓我們對(duì)ipa包中對(duì)文件進(jìn)行替換簽名。
利用 codesign 重簽名步驟
- 刪除插件(Plugin)和帶有插件的.app包(比如Watch)
- 對(duì)Frameworks里面的庫(kù)進(jìn)行重簽名
- 給可執(zhí)行文件 +x(可執(zhí)行)權(quán)限
- 添加描述文件(新建工程速缆,真機(jī)編譯獲冉翟省)
- 替換被簽名BundleID
- 通過描述文件創(chuàng)建權(quán)限文件.plist
- <key>application-identifier</key>
- <key>keychain-access-groups</key>
- <key>get-task-allow</key>
- <key>com.apple.developer.team-identifier</key>
- 通過授權(quán)文件(Entilements)重簽.app包
在重簽名過程中涉及到的終端命令:
- $security find-identity -v -p codesigning (查找并列出鑰匙串中可用于簽名的證書)
- $codesign -fs "證書串" 文件名(進(jìn)行簽名的替換)
- $chmod +x 可執(zhí)行文件(給可執(zhí)行文件添加可執(zhí)行權(quán)限)
- $security cms -D -i ../embedded.mobileprovision(查看描述文件)
- $codesign -fs "證書串" --no-strict --entitlements=權(quán)限文件.plist App包(App包重簽)
- $zip -ry 輸出文件 輸入文件(將輸入文件壓縮為輸出文件,進(jìn)行.ipa打包)
Xcode重簽名
- 創(chuàng)建一個(gè)
同名工程
艺糜,生成.app包 - 替換.app包
- 刪除插件(Plugin)和帶有插件的.app包(比如Watch)
- 對(duì)Frameworks里面的庫(kù)進(jìn)行重簽名
- 運(yùn)行項(xiàng)目
利用Xcode進(jìn)行Script重簽名
利用腳本重簽名剧董,其實(shí)就是利用了
codesign簽名
,只是將一個(gè)一個(gè)的步驟通過腳本指令自動(dòng)化
的去執(zhí)行破停。
# ${SRCROOT} 它是工程文件所在的目錄
TEMP_PATH="${SRCROOT}/Temp"
#資源文件夾翅楼,我們提前在工程目錄下新建一個(gè)APP文件夾,里面放ipa包
ASSETS_PATH="${SRCROOT}/APP"
#目標(biāo)ipa包路徑
TARGET_IPA_PATH="${ASSETS_PATH}/*.ipa"
#清空Temp文件夾
rm -rf "${SRCROOT}/Temp"
mkdir -p "${SRCROOT}/Temp"
#----------------------------------------
# 1. 解壓IPA到Temp下
unzip -oqq "$TARGET_IPA_PATH" -d "$TEMP_PATH"
# 拿到解壓的臨時(shí)的APP的路徑
TEMP_APP_PATH=$(set -- "$TEMP_PATH/Payload/"*.app;echo "$1")
# echo "路徑是:$TEMP_APP_PATH"
#----------------------------------------
# 2. 將解壓出來(lái)的.app拷貝進(jìn)入工程下
# BUILT_PRODUCTS_DIR 工程生成的APP包的路徑
# TARGET_NAME target名稱
TARGET_APP_PATH="$BUILT_PRODUCTS_DIR/$TARGET_NAME.app"
echo "app路徑:$TARGET_APP_PATH"
rm -rf "$TARGET_APP_PATH"
mkdir -p "$TARGET_APP_PATH"
cp -rf "$TEMP_APP_PATH/" "$TARGET_APP_PATH"
#----------------------------------------
# 3. 刪除extension和WatchAPP.個(gè)人證書沒法簽名Extention
rm -rf "$TARGET_APP_PATH/PlugIns"
rm -rf "$TARGET_APP_PATH/Watch"
#----------------------------------------
# 4. 更新info.plist文件 CFBundleIdentifier
# 設(shè)置:"Set : KEY Value" "目標(biāo)文件路徑"
/usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $PRODUCT_BUNDLE_IDENTIFIER" "$TARGET_APP_PATH/Info.plist"
#----------------------------------------
# 5. 給MachO文件上執(zhí)行權(quán)限
# 拿到MachO文件的路徑WeChat
APP_BINARY=`plutil -convert xml1 -o - $TARGET_APP_PATH/Info.plist|grep -A1 Exec|tail -n1|cut -f2 -d\>|cut -f1 -d\<`
#上可執(zhí)行權(quán)限
chmod +x "$TARGET_APP_PATH/$APP_BINARY"
#----------------------------------------
# 6. 重簽名第三方 FrameWorks
TARGET_APP_FRAMEWORKS_PATH="$TARGET_APP_PATH/Frameworks"
if [ -d "$TARGET_APP_FRAMEWORKS_PATH" ];
then
for FRAMEWORK in "$TARGET_APP_FRAMEWORKS_PATH/"*
do
#簽名
/usr/bin/codesign --force --sign "$EXPANDED_CODE_SIGN_IDENTITY" "$FRAMEWORK"
done
fi