A. 一文弄懂關於證書,簽名,ssl,android包簽名機制。
所有的概念都基於一個非常重要的基礎:
先感受下幾個概念
PKI。
PKI是公鑰基礎設施(Public Key Infrastructure) 包括PKI策略、軟硬體系統、證書機構CA、注冊機構RA、證書發布系統和PKI應用等。
我們關注就倆東西: PKCS 證書機構CA 。前者是定義加密演算法,簽名,證書相關的各種事情採用的協議。後者可以為我們頒發權威的證書。
PKCS :
PKCS(The Public-Key Cryptography Standards )是由美國RSA數據安全公司及其合作夥伴制定的一組公鑰密碼學標准,其中包括證書申請、證書更新、證書作廢表發布、擴展證書內容以及數字簽名、數字信封的格式等方面的一系列相關協議。RSA演算法可以做加密、解密、簽名、驗證,還有RSA的密鑰對存儲。這些都需要標准來規范,如何輸入,如何輸出,如何存儲等。
PKCS。全稱是公鑰密碼學標准, 目前共發布過 15 個標准,這些標准都是協議。總結一下 就是對加密演算法,簽名,證書協議的描述。下面列舉一些常用的協議,這些協議在本文都會對應上。
這些協議具體的實現就體現在openssl等工具中, 以及jdk工具keytool jdk java第三方庫bouncycastle。
比如用openssl 如何生成公/私鑰(PKCS#1)、簽名(PKCS#1 )、簽名請求文件(KCS#10)、 帶口令的私鑰(PKCS#8)。 含私鑰的證書(PKCS#12)、證書庫(PKCS#12)
其中涉及到演算法的基礎協議PKCS#1等,由於涉及到密碼學原理所以我們並不需要深究它,只要知道怎麼做就可以了。
現實中我們要解決這樣一種情況:
客戶端和伺服器之間的數據要進行加密。需要兩個達成同一個對稱秘鑰加密才行,那麼這個秘鑰如何生成,並在兩邊都能拿到,並保證傳輸過程中不被泄露。 這就用到非對稱加密了。 後續的傳輸,就能用這個 對稱秘鑰來加密和解密了。
還有這樣一個問題:
就是客戶端如何判斷服務端是否是合法的服務端。這就需要服務端有個id來證明它,而這個id 就是證書,而且必須是權威機構頒發的才能算是合法的。
因為客戶端即瀏覽器,認定證書合法的規則必須通過第三方來確認 即ca頒發的證書。否則就我可能進了一個假網站。
而這兩個問題 都是ssl協議要解決的內容。
所以ssl協議做了兩件事情,一是驗證身份,二是協商對稱秘鑰,並安全的傳輸。 而實現這個過程的關鍵數據模型就是證書, 通過證書中的ca對證書的簽名,實現了身份驗證,通過證書中的公鑰,實現對對稱秘鑰加密,從而實現數據保密。 其實還順手做了一件事情就是通過解密簽名比對hash,保證了數據完整性。
明白ssl協議 首先明白幾個重要的概念:
證書: 顧名思義就是提供了一種在Internet上驗證通信實體身份的方式,數字證書不是數字身份證,由權威公正的第三方機構,即CA(例如中國各地方的CA公司)中心簽發的證書, 就是可以認定是合法身份的。客戶端不需要證書。 證書是用來驗證服務端的。
一般的證書都是x509格式證書,這是一種標準的證書,可以和其他證書類型互相轉換。完整來說證書包含,證書的內容,包括 版本號, 證書序列號, hash演算法, 發行者名稱,有效期, 公鑰演算法,公鑰,簽名(證書原文以及原文hash一起簽名)而這個內容以及格式 都是標准化的,即x509格式 是一種標準的格式。
簽名: 就用私鑰對一段數據進行加密,得到的密文。 這一段數據在證書的應用上就是 對證書原文+原文hash進行簽名。
誰簽的名,就是用誰的私鑰進行加密。就像身份證一樣, 合法的身份證我們都依據是政府簽的,才不是假證, 那就是瀏覽器會有政府的公鑰,通過校驗(解密)簽名,如果能夠解密,就可以確定這個就是政府的簽名。就對了。
hash演算法 :對原始數據進行某種形式的信息提取,被提取出的信息就被稱作原始數據的消息摘要。比如,MD5和SHA-1及其大量的變體。 hash演算法具有不可逆性,無法從摘要中恢復出任何的原始消息。長度總是固定的。MD5演算法摘要的消息有128個比特位,SHA-1演算法摘要的消息最終有160比特位的輸出。
ca機構: 權威證書頒發機構,瀏覽器存有ca的公鑰,瀏覽器以此公鑰來驗證服務端證書的合法性。
證書的獲取: 生成證書申請文件.csr(涉及到PKCS#10定義的規范)後向ca機構申請。 或者自己直接通過生成私鑰就可以一步到位生成自簽名證書。 自簽名證書就是用自己的私鑰來簽名證書。
那麼為了體現到 證書身份認證、數據完整、保密性三大特性 ,證書的簡化模型可以認為包含以下兩個要素:伺服器公鑰,ca的簽名(被ca私鑰加密過的證書原文+原文hash),
身份認證:
瀏覽器存有ca公鑰,用ca公鑰解密網站發給你的證書中的簽名。如果能解密,說明該證書由ca頒發,證書合法。 否則瀏覽器就會報警告,問你是否信任這個證書,也就是這個網站。這時候的證書可以是任何人簽發的,可以自己簽發的。 但是中間人攻擊。 完全偽造新的證書, 這就沒有辦法了。 所以還是信任證書的時候要謹慎。
數據完整:
如果你信任該證書的話,這時候就會用證書中的公鑰去解密簽名,如果是ca簽發的證書,那麼之前就已經通過ca的公鑰去解密簽名了。 然後得到證書hash,然後在瀏覽器重新對證書做hash,兩者比對一致的話,說明證書數據沒有被篡改。
保密性:
使用證書的公鑰對對稱秘鑰加密保證傳輸安全,對稱秘鑰生成後,後續的傳輸會通過對稱秘鑰來在服務端和客戶端的加解密。
那麼ssl協議的具體過程就是:
4.網站接收瀏覽器發來的數據之後 使用自己的私鑰校驗簽名,並對原文進行hash 與解密出的hash 做比對檢查完整性。然後發送編碼改變通知,伺服器握手結束通知(所有內容做hash )。 發送給客戶端校驗。
5 客戶端校驗,校驗成功後,之後就用 對稱秘鑰進行通信了。
總共的過程是 c-s-c- s-c 四次握手。
四次握手簡單來說分別是:
1.請求獲取證書
2.服務端返回證書,客戶端驗證了證書的合法性和完整性,同時生成了對稱秘鑰。
3.客戶端把加密的 對稱秘鑰發給伺服器。伺服器檢查真實性和完整性。
4.服務端返回握手結束通知,客戶端再檢查一次真實性和完整性。
前兩次握手是明文, 後兩次握手是密文。 所以都要檢查身份真實性和數據完整性。
ca的作用:
ca起到一個權威中間人的角色,如果脫離了ca, 那麼證書還是證書,還能加密,保證數據完整性。 但是無法應用在客戶端去認定伺服器身份合法這個場景下。
下面就詳細說下 脫離了ca簽發的證書的應用:
自簽名證書:
證書如果沒有權威機構的簽名,就是沒有權威機構給你簽發身份證。 那麼這時候身份認證的場景變了。
這時候的認證場景就變成了,不再是某個官方權威說了算,而是假設第一次碰到這個證書,會認為,這個證書與之捆綁的實體之間是合法的並做記錄。如果當這個實體下次捆綁了另一個證書,那麼就是非法的。
這種情況常用於android中安裝和校驗app的時候,會先假設第一次安裝的是合法的應用,認定這個app證書中的公鑰是合法的公鑰。然後通過自簽名的證書,校驗簽名,就能實現後續安裝是否合法以及完整性。
android中的如何對app進行身份認定和不被篡改:
android系統在安裝app時候會進行校驗applicationId,applicationId 不同會認定為不同應用。相同應用,第二次安裝會校驗證書是否和之前app的證書相同,如果相同則兩個包很可能來自同一個身份。 如果證書不同,也就是該包被另一個身份用自己的私鑰重新簽名過,就會拒絕安裝。 然後通過公鑰來解密簽名,如果能解密,說明身份是ok的。否則拒絕安裝。比對解密簽名後的hash 與apk包內的cert.sf文件(該文件是apk內所有文件生成的hash文件)是否一致,如果相同則認定為沒有被篡改。
android在提交應用商店的問題:
應用商店也會校驗 後續的上傳和第一次上傳時的證書,以及類似上述的後續的一系列校驗。防止合法的開發者平台被盜後,上傳非法應用。
android在接入第三方sdk的問題:
接入第三方sdk 會提交applicationId 和 sha1 值。 這個sha1值就是對 證書原文的簽名後的sha1,也就是證書指紋。這個證書是證書庫里最初的那個證書(x509格式),而不是對apk簽名後生成的證書(PKCS#7)。一般的證書簽名的主體是證書原文本身,而對apk簽名還額外會對apk所有文件生成的hash值文件(cert.sf)進行一次簽名。
第三方平台會記錄 applicationId 與sha1 的對應關系。 當有假冒app試圖接入時候,由於會對app內的PKCS#7證書轉換為原始的x509格式證書,重新生成sha1值,與用戶提交sha1 比對, 如果相同則說明證書很可能是ok的。 因為sha1就是證書的指紋。 之後就會通過證書中的公鑰來校驗簽名,從而最終確認身份合法性以及信息完整性。
第三方平台之所以需要用戶去提交證書指紋sha1值,多了這一步,就意味著你的證書是可以更換的,一旦更換了證書,就必須提交新的指紋給我,然後我來做匹配。而應用商店沒有這個功能, 一旦你的證書的私鑰丟了, 那就必須重新建一個新的app。
總結來看證書的身份認定機制:
在ssl協議下,這種場景是 瀏覽器用於認定合法的伺服器身份。 在自簽名證書下,需要用戶選擇是否信任該證書。
在android app採用自簽名證書的場景下, 證書起到了 假設第一次的證書合法,公鑰合法,後續如果證書不一致或不能夠完成簽名校驗,就是非法。
證書庫:
證書庫應該滿足PKCS#12協議。 但是jdk提供了製作證書的工具keytool 可以生成keystore類型的證書庫,後綴為jks。 keystore pk12可以通過keytool命令互相轉換。
證書庫是個證書的容器, 可以用來創建數字證書。 在keystore證書庫中,所有的數字證書是以一條一條(採用別名alias區別)的形式存入證書庫的。證書庫中的證書格式為pk12,即包含私鑰。 如果導出證書的話, 可以導出為x509不包含私鑰的格式 或者pk12包含私鑰的證書。 也可以也可以用-import參數加一個證書或證書鏈到信任證書。
android中一般都採用讀取證書庫的方式,通過證書庫來創建一個證書,通過alias來區分。 所以在簽名的時候,一個alias是一個證書,不同的alias是不同的證書,不要搞錯了。
幾個關系:
證書和非對稱加密演算法的關系:
證書代表一個身份的主體,包含了非對稱秘鑰體系中的公鑰,以及用私鑰對證書簽名。這種組織結構,把非對稱加密演算法從加密的功能,拓寬到了用於身份認證,信息完整性上。這體現在了證書的作用。 本質還是利用了非對稱加密演算法的特性。
ssl協議和證書的關系。
因為證書解決了客戶端對伺服器的身份認證(自簽名證書除外),同時也解決了加密,和信息完整性,所以ssl協議基於證書來實現。
B. Android簽名機制之簽名文件和數字證書的作用
Android簽名機制目的是確保app的可靠通信,其一,要確定消息的來源確實是其申明
的那個人;其二,要保證信息在傳遞的過程中不被第三方篡改,即使被篡改了,也可以
發覺出來。
所謂數字簽名,就是為了解決這兩個問題而產生的,它是對非對稱加密技術與數字摘要
技術的一個具體的應用。
對於消息的發送者來說,先要生成一對公私鑰對,則穗將公鑰給消息的接收者。
如果消息的發送者有一天想給消息接收者發消息,在發送的信息中,除了要包含原始的
消息外,還要加上另外一段消息。這段消息通過如下兩步生成:
1)對要發送的原始消息提取消息摘要;
2)對提取的信息摘要用自己的私鑰加密。
通過這兩步得出的消息,就是所謂的原始信息的數字簽名。
而對於信息的接收者來說,他所收到的信息,將包含兩個部分,一是原始的消息內容,
二是附加的那段數字簽名。他將通過以下三步來驗證消息的真偽:
1)對原始消息部分提取消息摘要,注意這里使用的消息摘要演算法要和發送方使用的一孫游卜致;
2)對附加上的那段數字簽名,使用預先得到的公鑰解密;
3)比較前兩步所得到的兩段消息是否一致。如果一致,則表明消息確實是期望的發送者
發的,且內容沒有被篡改過;相反,如果不一致,則表明傳送的過程中一定出了問題,
消息不可信。
通過這種所謂的數字簽名技術,確實可以有效解決可靠通信的問題。如果原始消息在傳
送的過程中被篡改了,那麼在消息接收者那裡,對被篡改的消息提取的摘要肯定和原始
的不一樣。並且,由於篡改者沒有消息發送方的私鑰,即使他可以重新算出被篡改消息
的摘要,也不能偽造出數字簽名。
那麼數字簽名呢?
綜上所述,數字簽名其實就是只有信息的發送者才能產生的別人無法偽造的一段數字
串,這段數字串同時也是對信息的發送者發送信息真實性的一個有效證明。
不知道大家有沒有注意,前面講的這種數字簽名方法,有一個前提,就是消息的接收者
必須要事先得到正確的公鑰。如果一開始公鑰就被別人篡改了,那壞人就會被你當成好
人,而真正的消息發送者給你發的消息會被你視作無效的。而且,很多時候根本就不具
備事先溝通公鑰的信息通道。那麼如何保證公鑰的安全可信磨吵呢?這就要靠數字證書來解
決了。
所謂數字證書,一般包含以下一些內容:
證書的發布機構(Issuer)
證書的有效期(Validity)
消息發送方的公鑰
證書所有者(Subject)
數字簽名所使用的演算法
數字簽名
可以看出,數字證書其實也用到了數字簽名技術。只不過要簽名的內容是消息發送方的
公鑰,以及一些其它信息。但與普通數字簽名不同的是,數字證書中簽名者不是隨隨便
便一個普通的機構,而是要有一定公信力的機構。這就好像你的大學畢業證書上簽名的
一般都是德高望重的校長一樣。一般來說,這些有公信力機構的根證書已經在設備出廠
前預先安裝到了你的設備上了。所以,數字證書可以保證數字證書里的公鑰確實是這個
證書的所有者的,或者證書可以用來確認對方的身份。數字證書主要是用來解決公鑰的
安全發放問題。
綜上所述,總結一下,數字簽名和簽名驗證的大體流程如下圖所示:
引用鏈接: https://www.cnblogs.com/dacainiao/p/5842987.html
C. Android | 他山之石,可以攻玉!一篇文章看懂 v1/v2/v3 簽名機制
這篇文章的內容會涉及以下前置 / 相關知識,貼心的我都幫你准備好了,請享用~
數字簽名(Digital Signature)也叫作數字指紋(Digital Fingerprint),它是消息摘要演算法和非對稱加密演算法的結合體,能夠驗證數據的完整性,並且認證數據的來源 。
數據簽名演算法的模型分為兩個主要階段:
需要注意的是,Android 目前不對應用證書進行 CA 認證,應用可以由第三方(OEM、運營商、其他應用市場)簽名,也可以自行簽名。
應用 APK 其實是一種特殊的 Zip 壓縮包,無法避免惡意破解者解壓 / 反編譯修改內容,針對這個問題有何解決方案呢?他山之石,可以攻玉 ——數字簽名演算法。應用簽名正是數字簽名演算法的應用場景之一,與其他應用場景類似,目的無非是:
Android 平台上運行的每個應用都必須有開發者的簽名。在慧喚安裝應用時,軟體包管理器會驗證 APK 是否已經過適當簽名,安裝程序會拒絕沒有獲得簽名就嘗試安裝的應用。
軟體包管理器在安裝應用前會驗證應用摘要,如果破解者修改了 apk 里的內容,那麼摘要就不再匹配,驗證失敗(驗證流程見下文方案)。
截止至 Android 11,Android 支持以下三種應用簽名方案:
為了提高兼容性,必須按照 v1、v2、v3 的先後順序採用簽名方案,低版本平台會忽略高版本的簽名方案在 APK 中添加的額外數據。
v1 簽名方案是基於 Jar 的簽名。
首先,我們先來分析其簽名產物。 v1 簽名後會增加 META-INF 文件夾 ,其中會有如下三個文件。考慮到使用不同的證書和簽名方式,得到的文件名可能不同,因此你只要留意文件的後綴即可:
v1 簽名流程如下:
MANIFEST.MF(Message Digest File,摘要文件)
*.SF(Signature File,簽名文件)
驗證流程可以分為驗證簽名和驗證完整性兩個步驟:
驗證簽名步驟:
如果上述簽名驗證結果正確,才會驗證完整性:
以上任何步驟驗證失敗,則整個 APK 驗證失敗。
為了解決這些問題,Android 7.0 中引入了 APK 簽名方案 v2。
v2 簽名方案是一種 全文件簽名方案 ,該方案能夠發現對 APK 的受保護部分進行的所有更改,相對於 v1 簽名方案驗證速度更快,完整性覆蓋范圍更廣。
在分析 v2 簽名方案之前,我們先簡單了解一下 Zip 文件格式:
首先,我們先來分析其簽名產物。v2 簽名後會在 「條目內容區」和「中央目錄區」之間插入「APK 簽名分塊(APK Signing Block)」 。
從左到右邊,我們定義為區塊 1~4。
相對與 v1 簽名方案,v2 簽名方案不再以文件為單位計算摘要了,而敬坦是以 1 MB 為單位將文件拆分為多個連續的塊(chunk),每個分區的最後一個塊可能會小於 1 MB。
v2 簽亮碧桐名流程如下:
驗證流程可以分為驗證簽名和驗證完整性兩個步驟:
簽名方案 v3 支持密鑰輪換,應用能夠在 APK 更新過程中更改其簽名密鑰。
【累了,後面先不寫了...】
這一節,我們介紹基於 Android 應用簽名機制的衍生應用場景。
在 v1 方案中, MANIFEST.MF 和 *.SF 這兩個文件會記錄大量的文件名和文件摘要。如果 apk 中文件數很多,而且文件名很長,那麼這兩個文件會變得很大。使用 AndResGuard 工具,可以將文件名轉換為短路徑文件名,從而減少這兩個文件的大小。
在實際生產中,往往需要生成多個渠道的 APK 包,傳統的方法是使用 APKTool 逆向工具、Flavor + BuildType 等方案,這一類多渠道打包方案的缺點是耗時嚴重。隨著 Android 應用簽名方案的演進,演變出了不同的多渠道打包方案:
在 v1 方案中,我們提到了完整性校驗不覆蓋到 META-INF 文件夾的問題。有些多渠道打包方案就是利用了這個問題,在 META-INF 文件夾下添加空文件, 用空文件的名稱來作為渠道的唯一標識 ,就可以節省打包的時間,提高打渠道包的速度。
除了添加空文件的方法,還可以向 APK 添加 Zip Comment 來生成多渠道包(APK 本身就是特殊的 Zip 包)。
在 v2 簽名方案中,幾乎整個 APK 都納入保護范圍,如果向 APK 添加空文件或 Zip Comment 的話,在安裝時會報以下錯誤:
新背景下的多渠道打包方案,則是利用了 APK 簽名分塊(區塊 2)不受保護 & 欄位可擴展的特點 ,向區塊中添加多渠道信息(ID-Value),例如 美團多渠道打包方案 Walle 。
D. APK簽名機制原理詳解
眾所周知,Android系統在安裝Apk的過程中,會對Apk進行簽名校驗,校驗通過後才能安裝成功。那你知道簽名校驗的機制是什麼?具體校驗的是什麼內容嗎?申請第三方SDK(如微信支付)時填入的SAH1值是什絕頌高么?目前眾多的快速批量打包方案又是如何繞過簽名檢驗的?
我將通過一系列的文章來解開這些疑惑:
這篇文章先來介紹Apk簽名相關的基本知識。
要知道簽名是什麼,先來看為什麼需要簽名 。大家都知道,在消息通信時,必須至少解決兩個問題:一是確保消息來源的真實性,二是確保消息不會被第三方篡改。在安裝Apk時,同樣需要確保Apk來源的真實性,以及Apk沒有被第三方篡改。如何解決這兩個問題呢?方法就是開發者對Apk進行簽名:在Apk中寫入一個「指紋」。指紋寫入以後,Apk中有任何修改,都會導致這個指紋無效,Android系統在安裝Apk進行簽名校驗時就會不通過,從而保證了安全性。
要了解如何實現簽名,需要了解兩個基本概念:數字摘要和數字證書。
簡單來說,就是對一個任意長度的數據,通過一個Hash演算法計算後,都可以得到一個固定長度的二進制數據,這個數據就稱為「摘要」。摘要具有下面的幾個特徵:
前面已經說到,可以通過簽名來確保數據來源的可靠性和數據的不可篡改性。簽名就是在摘要的基礎上再進行一次加密,對摘要加密後的數據就可以當作數字簽名,在安裝Apk需要對簽名進行驗證,驗證通過才能繼續安裝。
這里有兩個過程:簽名過程 和 校驗過程。
先來說 簽名過程:
再來看 校驗過程:
這里有一個前提:接收方必須要知道發送方的公鑰和所使用的演算法。如果數字簽名和公鑰一起被篡改,接收方無法得知,還是會校驗通過。如何保證公鑰的可靠性呢?答案是數字證書,數字證書是身份認證機構(Certificate Authority)頒發的,包含了以下信息:
接收方收到消息後,先向CA驗證證書的合法性(根據證書的簽名、綁定的域名等信息。CA機構是權威的,可以保證這個過程的可靠性。)再進行簽名校驗。
需要注意的是,Apk的證書通常的自簽名的,也就是由開發者自己製作,沒有向CA機構申請。Android在安裝Apk時並沒有校驗證書本身的合法性,只是從證書中提取公鑰和加密演算法,這也正是對第三方Apk重新簽名後,還能夠繼續在沒有安裝這個Apk的系統中繼續安裝的原因。
我們在對Apk簽名時並沒有直接指定私鑰、公鑰和數字證書,而是使用keystore文件,這些信息都包含在了keystore文件中。根據編碼不同,keystore文件分為很多種,Android使用的是Java標准keystore格式JKS(Java Key Storage),所以通過Android Studio導出的keystore文件是以.jks結尾的。
keystore使用的證書標準是X.509,X.509標准也有多種編碼格式,常用的有兩種:pem(Privacy Enhanced Mail)和der(Distinguished Encoding Rules)。jks使用的是der格式,Android也支持直接使用pem格式的證書進行簽名,我們下面會介紹。
兩種證書編碼格式的區別:
X.509證書格式:
Android提供了兩種對Apk的簽名方式,一種是基於JAR的簽名方式,另一種是基於Apk的簽名方式,它們的主要區別在於使用的簽名文件不一樣:jarsigner使用keystore文件進行簽名;apksigner除了並尺支持使用keystore文件進行簽名外,還支持直接指定pem證書文件和私鑰進行簽名。
不知道大家有沒有注意一個問題,我們通過櫻御keytool或者AS生成一個keystore的時候( 簽署您的應用 ),除了要輸入keystore的密碼外,還要輸入一個alias和key的密碼。在簽名時,除了要指定keystore文件和密碼外,也要指定alias和key的密碼,這是為什麼呢?
原因是keystore是一個密鑰庫,也就是說它可以存儲多對密鑰和證書,keystore的密碼是用於保護keystore本身的,一對密鑰和證書是通過alias來區分的。從這里可以看出jarsigner是支持使用多個證書對Apk進行簽名的。apksigner也同樣支持,關於apksigner的使用介紹可以參考官方文檔 apksigner 。
ok,簽名的基本概念和校驗過程就介紹到這里,關於JAR簽名和V2簽名機制的詳細介紹,參考下面兩篇文章:
E. Android許可權機制
我們知道 Android 應用程序是沙箱隔離的,每個應用都有一個只有自己具有讀寫許可權的專用數據目錄。但是如果應用要訪問別人的組件或者一些設備上全局可訪問的資源,這時候許可權機制就能系統化地規范並強制各類應用程序的行為准則。
Android 安全性概覽
在 Android 中,一個許可權,本質上是一個字元串,一個可以表示執行特定操作的能力的字元串。比如說:訪問 SD 卡的能力,訪問通訊錄的能力,啟動或訪問一個第三方應用中的組件的能力。 許可權被授予了之後,首先會在內存和本地中有記錄,這在調用系統binder服務和其他應用組件時做鑒權依據,比如調用系統binder服務時會通過Binder.getCallingUid()拿到調用者的Uid,而Uid一般都是與應用包名一一對應的,再拿這個Uid到PMS里去查這個應用對應的許可權。 其次會按被授予的許可權將應用分到某個組。 可以參考 https://www.jianshu.com/p/a17c8bed79d9
自定義許可權的應用場景在於限制其它應用對本應用四大組件的訪問。具體用法可以參考 https://www.cnblogs.com/aimqqroad-13/p/8927179.html
pm list permissions -f 命令可以詳細查看 Android 所有預定義的許可權。
更詳細的許可權信息參考 https://developer.android.com/reference/android/Manifest.permission?hl=zh-cn#WRITE_EXTERNAL_STORAGE
可以看到一個許可權的信息包括:定義的包名、標簽、描述、 許可權組 和 保護級別 。
許可權根據設備的功能或特性分為多個組。如果應用已在相同許可權組中被授予另一危險許可權,系統將立即授予該許可權,如READ_CONTACTS和WRITE_CONTACTS。
SYSTEM_ALERT_WINDOW 和 WRITE_SETTINGS 由於其特殊性,其申請方式與其它許可權都不同。
其授予流程如下:
(關於 AppOpsManager 是什麼可以參考: https://segmentfault.com/a/1190000009214983 )
這里簡要分析下ActivityCompat#requestPermissions的流程:
更詳細的許可權授予流程源碼分析可以參考: https://segmentfault.com/a/1190000009214983
普通許可權: 清單文件中聲明即可。
危險許可權: 方式一: pm grant application_package android.permission.CHANGE_CONFIGURATION 方式二:appops set application_package permission_num 0/1
appops可以授予的許可權參考 android.app.AppOpsManager 中的聲明
系統簽名許可權: 方式一:將app遷移到system/priv-app目錄中。 方式二:看不懂,參考 https://blog.csdn.net/abcd_3344_abcd/article/details/50698759
android 4.4 訪問sd卡需要申請許可權。 您的應用在 Android 4.4 上運行時無法讀取外部存儲空間上的共享文件,除非您的應用具有 READ_EXTERNAL_STORAGE 許可權。也就是說,沒有此許可權,您無法再訪問 () 返回的目錄中的文件。但是,如果您僅需要訪問 getExternalFilesDir() 提供的您的應用特有目錄,那麼,您不需要 READ_EXTERNAL_STORAGE `許可權。
android 6.0 運行時許可權。 此版本引入了一種新的許可權模式,如今,用戶可直接在運行時管理應用許可權。這種模式讓用戶能夠更好地了解和控制許可權,同時為應用開發者精簡了安裝和自動更新過程。用戶可為所安裝的各個應用分別授予或撤銷許可權。 對於以 Android 6.0(API 級別 23)或更高版本為目標平台的應用,請務必在運行時檢查和請求許可權。要確定您的應用是否已被授予許可權,請調用新增的 checkSelfPermission() 方法。要請求許可權,請調用新增的 requestPermissions() 方法。即使您的應用並不以 Android 6.0(API 級別 23)為目標平台,您也應該在新許可權模式下測試您的應用。 如需了解有關在您的應用中支持新許可權模式的詳情,請參閱 使用系統許可權 。如需了解有關如何評估新模式對應用的影響的提示,請參閱 許可權最佳做法 。
android 7.+ 應用間共享文件要使用FileProvider。 對於面向 Android 7.0 的應用,Android 框架執行的 StrictMode API 政策禁止在您的應用外部公開 file://URI。如果一項包含文件 URI 的 intent 離開您的應用,則應用出現故障,並出現 FileUriExposedException 異常。 要在應用間共享文件,您應發送一項 content:// URI,並授予 URI 臨時訪問許可權。進行此授權的最簡單方式是使用 FileProvider `類。如需了解有關許可權和共享文件的詳細信息,請參閱 共享文件 。
android 8.+
同一許可權組的許可權在被授予了之後也需要顯式的再申請一次。
在 Android 8.0 之前,如果應用在運行時請求許可權並且被授予該許可權,系統會錯誤地將屬於同一許可權組並且在清單中注冊的其他許可權也一起授予應用。 對於針對 Android 8.0 的應用,此行為已被糾正。系統只會授予應用明確請求的許可權。然而,一旦用戶為應用授予某個許可權,則所有後續對該許可權組中許可權的請求都將被自動批准。 例如,假設某個應用在其清單中列出 READ_EXTERNAL_STORAGE 和 WRITE_EXTERNAL_STORAGE 。應用請求 READ_EXTERNAL_STORAGE ,並且用戶授予了該許可權。如果該應用針對的是 API 級別 24 或更低級別,系統還會同時授予 WRITE_EXTERNAL_STORAGE ,因為該許可權也屬於同一 STORAGE 許可權組並且也在清單中注冊過。如果該應用針對的是 Android 8.0,則系統此時僅會授予 READ_EXTERNAL_STORAGE ;不過,如果該應用後來又請求 WRITE_EXTERNAL_STORAGE ,則系統會立即授予該許可權,而不會提示用戶。
android 9
隱私許可權變更。
為了增強用戶隱私,Android 9 引入了若干行為變更,如限制後台應用訪問設備感測器、限制通過 Wi-Fi 掃描檢索到的信息,以及與通話、手機狀態和 Wi-Fi 掃描相關的新許可權規則和許可權組。
android 10
隱私權變更。
外部存儲訪問許可權范圍限定為應用文件和媒體,在後台運行時訪問設備位置信息需要許可權,針對從後台啟動 Activity 的限制等。
android 11
隱私許可權變更。
更詳細的版本變更請參考 https://developer.android.com/preview/privacy?hl=zh-cn
F. Android V1及V2簽名原理簡析
Android為了保證系統及應用的安全性,在安裝APK的時候需要校驗包的完整性,同時,對於覆蓋安裝的場景還要校驗新舊是否匹配,這兩者都是通過Android簽名機制來進行保證的,本文就簡單看下Android的簽名與校驗原理,分一下幾個部分分析下:
簽名是摘要與非對稱密鑰加密相相結合的產物,摘要就像內容的一個指紋信息,一旦內容被篡改,摘要就會改變,簽名是摘要的加密結果,摘要改變,簽名也會失效。Android APK簽名也是這個道理,如果APK簽名跟內容對應不起來,Android系統就認為APK內容被篡改了,從而拒絕安裝,以保證系統的安全性。目前Android有三種簽名V1、V2(N)、V3(P),本文只看前兩種V1跟V2,對於V3的輪密先不考慮。先看下只有V1簽名後APK的樣式:
再看下只有V2簽名的APK包樣式:
同時具有V1 V2簽名:
可以看到,如果只有V2簽名,那麼APK包內容幾乎是沒有改動的,META_INF中不會有新增文件,按Google官方文檔:在使用v2簽名方案進行簽名時,會在APK文件中插入一個APK簽名分塊,該分塊位於zip中央目錄部分之前並緊鄰該部分。在APK簽名分塊內, 簽名和簽名者身份信息會存儲在APK簽名方案v2分塊中,保證整個APK文件不可修改 ,如下圖:
而V1簽名是通過META-INF中的三個文件保證簽名及信息的完整性:
V1簽名是如何保證信息的完整性呢?V1簽名主要包含三部分內容,如果狹義上說簽名跟公鑰的話,僅僅在.rsa文件中,V1簽名的三個文件其實是一套機制,不能單單拿一個來說事,
如果對APK中的資源文件進行了替換,那麼該資源的摘要必定發生改變,如果沒有修改MANIFEST.MF中的信息,那麼在安裝時候V1校驗就會失敗,無法安裝,不過如果篡改文件的同時,也修改其MANIFEST.MF中的摘要值,那麼MANIFEST.MF校驗就可以繞過。
CERT.SF個人覺得有點像冗餘,更像對文件完整性的二次保證,同繞過MANIFEST.MF一樣,.SF校驗也很容易被繞過。
CERT.RSA與CERT.SF是相互對應的,兩者名字前綴必須一致,不知道算不算一個無聊的標准。看下CERT.RSA文件內容:
CERT.RSA文件裡面存儲了證書公鑰、過期日期、發行人、加密演算法等信息,根據公鑰及加密演算法,Android系統就能計算出CERT.SF的摘要信息,其嚴格的格式如下:
從CERT.RSA中,我們能獲的證書的指紋信息,在微信分享、第三方SDK申請的時候經常用到,其實就是公鑰+開發者信息的一個簽名:
除了CERT.RSA文件,其餘兩個簽名文件其實跟keystore沒什麼關系,主要是文件自身的摘要及二次摘要,用不同的keystore進行簽名,生成的MANIFEST.MF與CERT.SF都是一樣的,不同的只有CERT.RSA簽名文件。也就是說前兩者主要保證各個文件的完整性,CERT.RSA從整體上保證APK的來源及完整性,不過META_INF中的文件不在校驗范圍中,這也是V1的一個缺點。V2簽名又是如何保證信息的完整性呢?
前面說過V1簽名中文件的完整性很容易被繞過,可以理解 單個文件完整性校驗的意義並不是很大 ,安裝的時候反而耗時,不如採用更加簡單的便捷的校驗方式。V2簽名就不針對單個文件校驗了,而是 針對APK進行校驗 ,將APK分成1M的塊,對每個塊計算值摘要,之後針對所有摘要進行摘要,再利用摘要進行簽名。
也就是說,V2摘要簽名分兩級,第一級是對APK文件的1、3 、4 部分進行摘要,第二級是對第一級的摘要集合進行摘要,然後利用秘鑰進行簽名。安裝的時候,塊摘要可以並行處理,這樣可以提高校驗速度。
APK是先摘要,再簽名,先看下摘要的定義:Message Digest:摘要是對消息數據執行一個單向Hash,從而生成一個固定長度的Hash值,這個值就是消息摘要,至於常聽到的MD5、SHA1都是摘要演算法的一種。理論上說,摘要一定會有碰撞,但只要保證有限長度內碰撞率很低就可以,這樣就能利用摘要來保證消息的完整性,只要消息被篡改,摘要一定會發生改變。但是,如果消息跟摘要同時被修改,那就無從得知了。
而數字簽名是什麼呢(公鑰數字簽名),利用非對稱加密技術,通過私鑰對摘要進行加密,產生一個字元串,這個字元串+公鑰證書就可以看做消息的數字簽名,如RSA就是常用的非對稱加密演算法。在沒有私鑰的前提下,非對稱加密演算法能確保別人無法偽造簽名,因此數字簽名也是對發送者信息真實性的一個有效證明。不過由於Android的keystore證書是自簽名的,沒有第三方權威機構認證,用戶可以自行生成keystore,Android簽名方案無法保證APK不被二次簽名。
知道了摘要跟簽名的概念後,再來看看Android的簽名文件怎麼來的?如何影響原來APK包?通過sdk中的apksign來對一個APK進行簽名的命令如下:
其主要實現在 android/platform/tools/apksig 文件夾中,主體是ApkSigner.java的sign函數,函數比較長,分幾步分析
先來看這一步,ApkUtils.findZipSections,這個函數主要是解析APK文件,獲得ZIP格式的一些簡單信息,並返回一個ZipSections,
ZipSections包含了ZIP文件格式的一些信息,比如中央目錄信息、中央目錄結尾信息等,對比到zip文件格式如下:
獲取到 ZipSections之後,就可以進一步解析APK這個ZIP包,繼續走後面的簽名流程,
可以看到先進行了一個V2簽名的檢驗,這里是用來簽名,為什麼先檢驗了一次?第一次簽名的時候會直接走這個異常邏輯分支,重復簽名的時候才能獲到取之前的V2簽名,懷疑這里獲取V2簽名的目的應該是為了排除V2簽名,並獲取V2簽名以外的數據塊,因為簽名本身不能被算入到簽名中,之後會解析中央目錄區,構建一個DefaultApkSignerEngine用於簽名
先解析中央目錄區,獲取AndroidManifest文件,獲取minSdkVersion(影響簽名演算法),並構建DefaultApkSignerEngine,默認情況下V1 V2簽名都是打開的。
第五步與第六步的主要工作是:apk的預處理,包括目錄的一些排序之類的工作,應該是為了更高效處理簽名,預處理結束後,就開始簽名流程,首先做的是V1簽名(默認存在,除非主動關閉):
步驟7、8、9都可以看做是V1簽名的處理邏輯,主要在V1SchemeSigner中處理,其中包括創建META-INFO文件夾下的一些簽名文件,更新中央目錄、更新中央目錄結尾等,流程不復雜,不在贅述,簡單流程就是:
這里特殊提一下重復簽名的問題: 對一個已經V1簽名的APK再次V1簽名不會有任何問題 ,原理就是:再次簽名的時候,會排除之前的簽名文件。
可以看到目錄、META-INF文件夾下的文件、sf、rsa等結尾的文件都不會被V1簽名進行處理,所以這里不用擔心多次簽名的問題。接下來就是處理V2簽名。
V2SchemeSigner處理V2簽名,邏輯比較清晰,直接對V1簽名過的APK進行分塊摘要,再集合簽名,V2簽名不會改變之前V1簽名後的任何信息,簽名後,在中央目錄前添加V2簽名塊,並更新中央目錄結尾信息,因為V2簽名後,中央目錄的偏移會再次改變:
簽名校驗的過程可以看做簽名的逆向,只不過覆蓋安裝可能還要校驗公鑰及證書信息一致,否則覆蓋安裝會失敗。簽名校驗的入口在PackageManagerService的install里,安裝官方文檔,7.0以上的手機優先檢測V2簽名,如果V2簽名不存在,再校驗V1簽名,對於7.0以下的手機,不存在V2簽名校驗機制,只會校驗V1,所以,如果你的App的miniSdkVersion<24(N),那麼你的簽名方式必須內含V1簽名:
校驗流程就是簽名的逆向,了解簽名流程即可,本文不求甚解,有興趣自己去分析,只是額外提下覆蓋安裝,覆蓋安裝除了檢驗APK自己的完整性以外,還要校驗證書是否一致只有證書一致(同一個keystore簽名),才有可能覆蓋升級。覆蓋安裝同全新安裝相比較多了幾個校驗
這里只關心證書部分:
Android V1及V2簽名簽名原理簡析
僅供參考,歡迎指正
G. Android基礎『V1V2V3簽名』
基礎概念
簽名:在 APK 中寫入一個「指紋」。指紋寫入以後,APK 中有任何修改,都會導致這個指紋無效,Android 系統在安裝 APK 進行簽名校驗時就會不通過,從而保證了安全性。
摘要演算法: 使用一段簡單的看上去隨機的不可逆向的固定長度的字元串來表示一個文件的唯一性。 常見的摘要演算法如MD5(128個比特位)、SHA-1演算法(160/192/256個比特位)。
公鑰密碼體制:也稱非對稱演算法,特點是 公鑰是公開的 ,私鑰是保密的。常見的如:RSA。
展開討論一下RSA:
Android中的簽名方案
V1 :基於jarsigner(JDK自帶工具,使用keystore文件進行簽名) 或 apksigner(Android專門提供的,使用pk8、x509.pem進行簽名)。keystore和pk8/x509.pem可以相互轉換。
簽名原理:首先keystore文件包含一個MD5和一個SHA1摘要。 這也是很多開放平台需要我們上傳的摘要數據 。
簽名APK後會在META-INF文件夾下生產CERT.RSA、CERT.SF、MANIFEST.MF三個文件。
在apk中,/META-INF文件夾中保存著apk的簽名信息,一般至少包含三個文件,[CERT].RSA,[CERT].SF和MANIFEIST.MF文件。這三個文件就是對apk的簽名信息。
MANIFEST.MF中包含對apk中除了/META-INF文件夾外所有文件的簽名值,簽名方法是先SHA1()(或其他hash方法)在base64()。存儲形式是:Name加[SHA1]-Digest。
[CERT].SF是對MANIFEST.MF文件整體簽名以及其中各個條目的簽名。一般地,如果是使用工具簽名,還多包括一項。就是對MANIFEST.MF頭部信息的簽名,關於這一點前面源碼分析中已經提到。
[CERT].RSA包含用私鑰對[CERT].SF的簽名以及包含公鑰信息的數字證書。
是否存在簽名偽造可能:
修改(含增刪改)了apk中的文件,則:校驗時計算出的文件的摘要值與MANIFEST.MF文件中的條目不匹配,失敗。
修改apk中的文件+MANIFEST.MF,則:MANIFEST.MF修改過的條目的摘要與[CERT].SF對應的條目不匹配,失敗。
修改apk中的文件+MANIFEST.MF+[CERT].SF,則:計算出的[CERT].SF簽名與[CERT].RSA中記錄的簽名值不匹配,失敗。
修改apk中的文件+MANIFEST.MF+[CERT].SF+[CERT].RSA,則:由於證書不可偽造,[CERT].RSA無法偽造。
V2 :7.0新增的
簽名後的包會被分為四部分
1. Contents of ZIP entries(from offset 0 until the start of APK Signing Block)
2. APK Signing Block
3. ZIP Central Directory
4. ZIP End of Central Directory
新應用簽名方案的簽名信息會被保存在區塊2(APK Signing Block) 中, 而區塊1( Contents of ZIP entries )、區塊3( ZIP Central Directory )、區塊4( ZIP End of Central Directory )是受保護的, 在簽名後任何對區塊1、3、4的修改都逃不過新的應用簽名方案的檢查 。
V3 :9.0新增的
格式大體和 v2 類似,在 v2 插入的簽名塊(Apk Signature Block v2)中,又添加了一個新快(Attr塊) 。
在這個新塊中,會記錄我們之前的簽名信息以及新的簽名信息,以 密鑰轉輪的方案,來做簽名的替換和升級。這意味著,只要舊簽名證書在手,我們就可以通過它在新的 APK 文件中,更改簽名 。
v3 簽名新增的新塊(attr)存儲了所有的簽名信息,由更小的 Level 塊,以 鏈表 的形式存儲。
其中每個節點都包含用於為之前版本的應用簽名的簽名證書,最舊的簽名證書對應根節點,系統會讓每個節點中的證書為列表中下一個證書簽名,從而為每個新密鑰提供證據來證明它應該像舊密鑰一樣可信。
這個過程有點類似 CA 證書的證明過程,已安裝的 App 的舊簽名,確保覆蓋安裝的 APK 的新簽名正確,將信任傳遞下去。
注意: 簽名方式只支持升級不支持降級,如安裝了V2的包,不能覆蓋替換為V1的包。
參考
Android App簽名(證書)校驗過程源碼分析
新一代開源Android渠道包生成工具Walle
Android 簽名機制 v1、v2、v3