提綱
初步了解:是什么檬输,為什么需要枚粘,有什么好處灾杰,怎么加密和驗證蚊丐,怎么使用,要點補充
簽名方案:v1,v2,v3簽名及校驗流程艳吠,版本缺陷
初步了解Android簽名機制
? ? Android應(yīng)用程序的簽名(是什么)
???????? - 在Android 系統(tǒng)中麦备,所有安裝到系統(tǒng)的應(yīng)用程序都必有一個數(shù)字證書,要求每一個安裝進系統(tǒng)的應(yīng)用程序都是經(jīng)過數(shù)字證書簽名的昭娩,此數(shù)字證書用于標識應(yīng)用程序的作者和在應(yīng)用程序之間建立信任關(guān)系
? ? ? 簽名的必要性(為什么需要)
????? -證明 APK的所有者凛篙。通過對 Apk 進行簽名,開發(fā)者可以證明對 Apk 的所有權(quán)和控制權(quán)栏渺,可用于安裝和更新其應(yīng)用呛梆。而在 Android 設(shè)備上的安裝 Apk ,如果是一個沒有被簽名的 Apk磕诊,則會被拒絕安裝填物。
????? -允許 Android市場和設(shè)備校驗APK的正確性。在安裝 Apk 的時候霎终,軟件包管理器也會驗證 Apk 是否已經(jīng)被正確簽名融痛,并且通過簽名證書和數(shù)據(jù)摘要驗證是否合法沒有被篡改。只有確認安全無篡改的情況下神僵,才允許安裝在設(shè)備上。
? ? ? 統(tǒng)一簽名的好處(有什么好處)
????? - 有利于程序升級覆劈。當新版程序和舊版程序的數(shù)字證書相同時保礼,Android 系統(tǒng)才會認為這兩個程序是同一個程序的不同版本沛励。如果新版程序和舊版程序的數(shù)字證書不相同,則Android 系統(tǒng)認為他們是不同的程序炮障,并產(chǎn)生沖突目派,會要求新程序更改包名。
????? -有利于程序的模塊化設(shè)計和開發(fā)胁赢。Android 系統(tǒng)允許擁有同一個數(shù)字簽名的程序運行在一個進程中企蹭,Android程序會將他們視為同一個程序。所以開發(fā)者可以將自己的程序分模塊開發(fā)智末,而用戶只需要在需要的時候下載適當?shù)哪K
????? -可以通過權(quán)限(permission)的方式在多個程序間共享數(shù)據(jù)和代碼谅摄。Android提供了基于數(shù)字證書的權(quán)限賦予機制,應(yīng)用程序可以和其他的程序共享概功能或者數(shù)據(jù)給那那些與自己擁有相同數(shù)字證書的程序系馆。如果某個權(quán)限(permission)的protectionLevel是signature送漠,則這個權(quán)限就只能授予那些跟該權(quán)限所在的包擁有同一個數(shù)字證書的程序。
? ? ? 簽名的驗證方式(怎么加密和驗證的)
? ? ? ? ?發(fā)送者把文件用算法生成摘要由蘑,再用私鑰對摘要進行加密闽寡,把證書、文件尼酿、加密串爷狈、公鑰發(fā)給接收端。接收端獲取到之后裳擎,根據(jù)證書認真發(fā)送者身份涎永,用公鑰對加密串進行解密,再對文件也用算法生成摘要句惯,對比解密之后的信息和摘要的信息是否相同土辩。
簽名的動作是執(zhí)行在打包流程的后期
靜態(tài)資源整理->編譯源碼,處理得到dex文件->合成APK->簽名抢野,對齊
? ? ? 對Android應(yīng)用程序簽名(怎么使用的)
使用方面只需要兩步
第一步是生成密鑰拷淘,在as中就有方便的頁面生成密鑰
第二步則是使用密鑰簽名,常見的在gradle中設(shè)置好signingconfig指孤,不同編譯下的使用
這里舉例的使用方式是比較常用有效的启涯,也有命令行,gui界面的方式進行設(shè)置恃轩。在ppt注釋中有鏈接结洼,有興趣可以看看這些連接
Android APK命令行實現(xiàn)V1、V2簽名及驗證http://www.reibang.com/p/e00f9bb12340
Android 開發(fā)者->Android Studio->用戶指南->為您的應(yīng)用簽名https://developer.android.com/studio/publish/app-signing
? ? ? 關(guān)于數(shù)字證書的要點補充
??????? -所有的應(yīng)用程序都必須有數(shù)字證書(包括未發(fā)布的應(yīng)用)叉跛。Android 系統(tǒng)不會安裝一個沒有數(shù)字證書的應(yīng)用程序松忍。
????????? 從IDE 中運行或調(diào)試您的項目時,Android Studio 將自動使用通過 Android SDK 工具生成的調(diào)試證書為您的應(yīng)用簽名筷厘。當您首次在 Android Studio 中運行或調(diào)試項目時鸣峭,IDE 會自動在 `$HOME/.android/debug.keystore` 中創(chuàng)建調(diào)試密鑰庫和證書宏所,并設(shè)置密鑰庫和密鑰密碼。
??????? -在簽名時摊溶,需要考慮數(shù)字證書的有效期爬骤。數(shù)字證書都是有有效期的,Android 只是在應(yīng)用程序安裝的時候才會檢查證書的有效期莫换。如果程序已經(jīng)安裝在系統(tǒng)中霞玄,即使證書過期也不會影響程序的正常功能。一旦數(shù)字證書失效拉岁,持有改數(shù)字證書的程序?qū)⒉荒苷I墶?/p>
Android中的簽名方案
Android 的簽名方案坷剧,發(fā)展到現(xiàn)在,不是一蹴而就的膛薛。Android
現(xiàn)在已經(jīng)有三種應(yīng)用簽名方案听隐,v1升級到v3
v1 到 v2 是顛覆性的,為了解決JAR簽名方案的安全性問題哄啄,而到了v3方案雅任,其實結(jié)構(gòu)上并沒有太大的調(diào)整,可以理解為v2簽名方案的升級版咨跌,有一些資料也把它稱之為v2+方案沪么。
簽名方案的升級,就是向下兼容的锌半,所以只要使用得當禽车,這個過程對開發(fā)者是透明的。
v1 到 v2 方案的升級刊殉,對開發(fā)者影響最大的殉摔,就是渠道打包簽署的問題。這個后續(xù)會說到记焊。
簽名工具有兩個jarsigner 和 apksigner逸月。它們的簽名算法沒什么區(qū)別,主要是簽名使用的文件不同遍膜。
V1(<7.0)基于jar簽名碗硬,jarsigner
V2(>=7.0)基于apk簽名,apksigner
V3(>=9.0)基于apk簽名瓢颅,apksigner恩尾,支持密鑰輪轉(zhuǎn)
Android提供了兩種對Apk的簽名方式,區(qū)別:
1挽懦、jarsigner是為jar簽名設(shè)計的翰意,apksigner是為apk設(shè)計的;
2、jarsigner不能生成v2簽名猎物,apksigner可以虎囚;
3、jarsigner沒有判斷4.2(api17)以下蔫磨,不能用SHA-256摘要算法;
4圃伶、支持的算法jarsigner使用keystore文件進行簽名堤如;
apksigner除了支持使用keystore文件進行簽名外,還支持直接指定pem證書文件和私鑰進行簽名窒朋。
5搀罢、與對齊的關(guān)系;
了解V1簽名
通過解壓工具打開apk文件侥猩,會發(fā)現(xiàn)有一個META-INF目錄榔至,該目錄中有3個文件,這3個文件是簽名以后生成的欺劳,顯然與簽名相關(guān)唧取,我們依次看這幾個文件中的內(nèi)容:MANIFEST.MF、CERT.SF和CERT.RSA划提。
MANIFEST.MF:APK中所有原始文件的數(shù)據(jù)摘要的Base64編碼,而數(shù)據(jù)摘要算法就是SHA1或者SHA256
CERT.SF:
1》計算這個MANIFEST.MF文件的數(shù)據(jù)摘要(如SHA1算法)枫弟,再經(jīng)過BASE64編碼后,記錄在CERT.SF主屬性塊(在文件頭上)的“SHA1-Digest-Manifest”屬性值值下
2》逐條計算MANIFEST.MF文件中每一個塊的數(shù)據(jù)摘要鹏往,并經(jīng)過BASE64編碼后淡诗,記錄在CERT.SF中的同名塊中,屬性的名字是“SHA1-Digest
CERT.RSA:把之前生成的 CERT.SF文件伊履, 用私鑰計算出簽名, 然后將簽名以及包含公鑰信息的數(shù)字證書一同寫入生成CERT.RSA文件韩容,用openssl命令才能查看其內(nèi)容:openssl pkcs7 -inform DER -in CERT.RSA -noout -print_certs –text
V1簽名的詳細流程(具體可參考SignApk.java)? ? ? ??
生成簽名過程
1.對APK內(nèi)部所有文件(條目),提取摘要后BASE64生成指紋清單MANIFEST.MF;
2.對指紋清單提取摘要后BASE64生成CERT.SF;
3.對CERT.SF用私鑰加密并且附加公鑰生成CERT.RSA.
整個簽名機制的最終產(chǎn)物就是MANIFEST.MF唐瀑、CERT.SF群凶、CERT.RSA三個文件
V1安裝驗證簽名流程
1.校驗CERT.SF文件
計算CERT.SF的摘要,與通過簽名者公鑰解密得到的摘要進行對比介褥,如果一致進行下一步座掘。
2.檢驗MANIFEST.MF文件
計算MANIFEST.MF文件的摘要,與CERT.SF主屬性記錄的摘要進行對比柔滔。
3.檢驗apk中每個文件的完整性
逐步計算apk中每個文件的摘要溢陪。與MANIFEST.MF中的記錄進行對比,如果一致睛廊,則校驗通過形真。
如果是升級安裝,還需校驗證書簽名是否與已安裝的一致。
在安裝APK時咆霜,Android系統(tǒng)會校驗簽名邓馒,檢查APK是否被篡改。代碼流程是:PackageManagerService.java ->
PackageParser.java蛾坯,PackageParser類負責V1簽名的具體校驗光酣。
V1簽名是怎么保證APK文件不被篡改的?
首先脉课,如果破壞者修改了APK中的任何文件救军,那么被篡改文件的數(shù)據(jù)摘要的Base64編碼就和MANIFEST.MF文件的記錄值不一致,導致校驗失敗倘零。
?其次唱遭,如果破壞者同時修改了對應(yīng)文件在MANIFEST.MF文件中的Base64值,那么MANIFEST.MF中對應(yīng)數(shù)據(jù)塊的Base64值就和CERT.SF文件中的記錄值不一致呈驶,導致校驗失敗拷泽。
最后,如果破壞者更進一步袖瞻,同時修改了對應(yīng)文件在CERT.SF文件中的Base64值司致,那么CERT.SF的數(shù)字簽名就和CERT.RSA記錄的簽名不一致,也會校驗失敗虏辫。
那有沒有可能繼續(xù)偽造CERT.SF的數(shù)字簽名那蚌吸?理論上不可能,因為破壞者沒有開發(fā)者的私鑰砌庄。那破壞者是不是可以用自己的私鑰和數(shù)字證書重新簽名那羹唠,這倒是完全可以!
綜上所述娄昆,任何對APK文件的修改佩微,在安裝時都會失敗,除非對APK重新簽名萌焰。但是相同包名哺眯,不同簽名的APK也是不能同時安裝的。
V1簽名的缺陷(也是迭代V2的原因)
?不夠安全扒俯,簽名驗證范圍僅驗證 元數(shù)據(jù) 以外的 文件 條目奶卓,這里說的元數(shù)據(jù)主要指meta-inf目錄下的文件
v1 簽名方案,并不會保護
Apk 內(nèi)的所有內(nèi)容撼玄,有一些例外部分夺姑,被修改也并不會導致簽名失效
這樣,在驗證APK 簽名的時候掌猛,就需要處理大量不可信(尚未經(jīng)過驗證)的數(shù)據(jù)結(jié)構(gòu)盏浙,然后還需要過濾并舍棄掉這部分不受簽名保護的數(shù)據(jù),再進行簽名校驗。也就是說你可以在已簽名的文件中废膘,增加一些不被簽名保護的內(nèi)容竹海,這將導致受攻擊的可能增大。
?不夠迅速:驗證簽名的時候,須解壓所有已壓縮的文件條目進行數(shù)據(jù)摘要的校驗
v1方案是對 APK 內(nèi)部的被保護的原始文件(未壓縮),單獨進行計算數(shù)據(jù)摘要,所以在驗證期間,也需要對每個文件進行解壓再進行簽名校驗火诸,來驗證是否被篡改。所以在驗證APK 簽名的時候蚂会,必須解壓 APK 的所有已壓縮的文件條目進行數(shù)據(jù)摘要的校驗腻菇,而這些,都將需要花費更多的時間和內(nèi)存惦积。
V2簽名(Android 7.0引入)
引入目的:解決v1的問題
?MANIFEST.MF中的數(shù)據(jù)摘要是基于原始未壓縮文件計算的接校。因此在校驗時,需要先解壓出原始文件狮崩,才能進行校驗蛛勉。而解壓操作無疑是耗時的。
?V1簽名僅僅校驗APK第一部分中的文件睦柴,缺少對APK的完整性校驗诽凌。因此,在簽名后坦敌,我們還可以修改APK文件侣诵,例如:通過zipalign進行字節(jié)對齊后,仍然可以正常安裝狱窘。
怎么解決的
?V2簽名是對APK本身進行數(shù)據(jù)摘要計算杜顺,不存在解壓APK的操作,減少了校驗時間蘸炸。
?V2簽名是針對整個APK進行校驗(不包含簽名塊本身)躬络,因此對APK的任何修改(包括添加注釋、zipalign字節(jié)對齊)都無法通過V2簽名的校驗搭儒。
某實驗室數(shù)據(jù)(Nexus 6P穷当、Android 7.1.1)可供參考
了解APK文件結(jié)構(gòu)(V1)
APK文件本質(zhì)上是一個ZIP壓縮包,而ZIP格式是固定的淹禾,主要由三部分構(gòu)成馁菜,如下圖所示
?第一部分是內(nèi)容塊,所有的壓縮文件都在這部分稀拐。每個壓縮文件都有一個local file header火邓,主要記錄了文件名、壓縮算法、壓縮前后的文件大小铲咨、修改時間躲胳、CRC32值等。
?第二部分稱為中央目錄纤勒,包含了多個central directory file header(和第一部分的local file header一一對應(yīng))坯苹,每個中央目錄文件頭主要記錄了壓縮算法、注釋信息摇天、對應(yīng)local file header的偏移量等粹湃,方便快速定位數(shù)據(jù)。
?最后一部分是EOCD泉坐,主要記錄了中央目錄大小为鳄、偏移量和ZIP注釋信息等
根據(jù)之前的V1簽名和校驗機制可知,V1簽名只會檢驗第一部分的所有壓縮文件腕让,而不理會后兩部分內(nèi)容孤钦。
了解APK文件結(jié)構(gòu)(V2區(qū)別于V1)
v2 簽名會在原先APK塊中增加了一個新的塊(簽名塊),新的塊存儲了簽名纯丸、摘要偏形、簽名算法、證書鏈和額外屬性等信息觉鼻,這個塊有特定的格式俊扭。
APK簽名塊位于中央目錄之前,文件數(shù)據(jù)之后坠陈。V2簽名同時修改了EOCD中的中央目錄的偏移量萨惑,使簽名后的APK還符合ZIP結(jié)構(gòu)。
v2 簽名塊負責保護第1畅姊、3咒钟、4 部分的完整性,以及第2部分包含的APK 簽名方案v2分塊中的signed data分塊的完整性若未。
V2簽名原理
V2簽名塊的生成(可參考ApkSignerV2)
V2簽名塊的生成可參考ApkSignerV2朱嘴,整體結(jié)構(gòu)和流程如圖
首先,根據(jù)多個簽名算法粗合,計算出整個APK的數(shù)據(jù)摘要萍嬉,組成左上角的APK數(shù)據(jù)摘要集;
接著隙疚,把最左側(cè)一列的數(shù)據(jù)摘要壤追、數(shù)字證書和額外屬性組裝起來,形成類似于V1簽名的“MF”文件(第二列第一行)供屉;
其次行冰,再用相同的私鑰溺蕉,不同的簽名算法,計算出“MF”文件的數(shù)字簽名悼做,形成類似于V1簽名的“SF”文件(第二列第二行)疯特;
然后,把第二列的類似MF文件肛走、類似SF文件和開發(fā)者公鑰一起組裝成通過單個keystore簽名后的v2簽名塊(第三列第一行)漓雅。
最后,把多個keystore簽名后的簽名塊組裝起來朽色,就是完整的V2簽名塊了(Android中允許使用多個keystore對apk進行簽名)邻吞。
簡而言之,單個keystore簽名塊主要由三部分組成葫男,分別是上圖中第二列的三個數(shù)據(jù)塊:類似MF文件抱冷、類似SF文件和開發(fā)者公鑰,其結(jié)構(gòu)如圖2所示
V2簽名的校驗流程(PackageManagerService.java
-> PackageParser.java -> ApkSignatureSchemeV2Verifier.java)
Android Gradle Plugin2.2之上默認會同時開啟V1和V2簽名梢褐,同時包含V1和V2簽名的CERT.SF文件會有一個特殊的主屬性徘层,該屬性會強制APK走V2校驗流程(7.0之上),以充分利用V2簽名的優(yōu)勢(速度快和更完善的校驗機制)
同時包含V1和V2簽名的APK的校驗流程利职,優(yōu)先校驗V2,沒有或者不認識V2瘦癌,則校驗V1猪贪。具體校驗類似v1,但是不是校驗一個個文件讯私,而是apk的分段热押,如下圖所示
V2簽名是怎么保證APK不被篡改的?
首先斤寇,如果破壞者修改了APK文件的任何部分(簽名塊本身除外)桶癣,那么APK的數(shù)據(jù)摘要就和“MF”數(shù)據(jù)塊中記錄的數(shù)據(jù)摘要不一致,導致校驗失敗娘锁。
其次牙寞,如果破壞者同時修改了“MF”數(shù)據(jù)塊中的數(shù)據(jù)摘要,那么“MF”數(shù)據(jù)塊的數(shù)字簽名就和“SF”數(shù)據(jù)塊中記錄的數(shù)字簽名不一致莫秆,導致校驗失敗间雀。
然后,如果破壞者使用自己的私鑰去加密生成“SF”數(shù)據(jù)塊镊屎,那么使用開發(fā)者的公鑰去解密“SF”數(shù)據(jù)塊中的數(shù)字簽名就會失斎切;
最后缝驳,更進一步连锯,若破壞者甚至替換了開發(fā)者公鑰归苍,那么使用數(shù)字證書中的公鑰校驗簽名塊中的公鑰就會失敗,這也正是數(shù)字證書的作用运怖。
綜上所述拼弃,任何對APK的修改,在安裝時都會失敗驳规,除非對APK重新簽名肴敛。但是相同包名,不同簽名的APK也是不能同時安裝的吗购。
V2簽名注意點補充
Q1:V2簽名后EOCD的中央目錄偏移量更改了医男,安裝時怎么通過校驗的?
A1:Android系統(tǒng)在校驗APK的數(shù)據(jù)摘要時捻勉,首先會把EOCD的中央目錄偏移量替換成簽名塊的偏移量镀梭,然后再計算數(shù)據(jù)摘要。而簽名塊的偏移量就是v2簽名之前的中央目錄偏移量
具體代碼邏輯踱启,可參考ApkSignatureSchemeV2Verifier.java报账。截圖自https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/util/apk/ApkSigningBlockUtils.java
Q2:APK先V1簽名,還是V2先簽名埠偿?
A2:先V1透罢,再V2,因為JAR簽名需要修改zip數(shù)據(jù)區(qū)和中央目錄的內(nèi)容冠蒋,先使用V2簽名再JAR簽名會破壞V2簽名的完整性羽圃。
Q3:刪掉V2簽名,能否繞過V2簽名抖剿?
A3:不行朽寞,簽名CERT.SF文件中的標志也是防回滾的保護,防止刪除高版本簽名斩郎,僅驗證低版本簽名
Q4:APK簽名時脑融,只有V2簽名,沒有V1簽名行不行缩宜?
A4:這種情況是可以編譯通過的肘迎,并且在Android 7.0之上也可以正確安裝和運行。但是7.0之下脓恕,因為不認識V2膜宋,又沒有V1簽名,所以會報沒有簽名的錯誤炼幔。
V2簽名的缺陷:沒支持簽名的更新(迭代v3原因)
?簽名有默認25年的有效期限
?簽名泄漏想替換
V3簽名(Android 9.0 引入)
V3簽名結(jié)構(gòu)基于V2秋茫, 增加支持密鑰輪轉(zhuǎn)
V3 簽名新增的新塊(attr)存儲了所有的簽名信息,由更小的 Level 塊乃秀,以鏈表的形式存儲肛著。
其中每個節(jié)點都包含用于為之前版本的應(yīng)用簽名的簽名證書圆兵,最舊的簽名證書對應(yīng)根節(jié)點,系統(tǒng)會讓每個節(jié)點中的證書為列表中下一個證書簽名枢贿,從而為每個新密鑰提供證據(jù)來證明它應(yīng)該像舊密鑰一樣可信殉农。
V3 方案還沒有正式開放,在最新版的Build Tools 版本28.0.3中的Apksigner局荚,尚不支持V3的APK簽名方案超凳。想嘗鮮可以通過源代碼自行編譯。
https://developer.android.google.cn/studio/command-line/apksigner#usage-verify
到這里耀态,就了解完了簽名的機制轮傍,下一篇講下android的打包機制。感謝支持
?參考鏈接:
?應(yīng)用簽名 https://source.android.google.cn/security/apksigning
?Android簽名機制v1首装、v2创夜、v3 http://www.reibang.com/p/9ca1d6f3f083
?APK簽名機制原理詳解http://www.reibang.com/p/286d2b372334