來源:Yury Zhauniarovich | Publications
譯者:飛龍
在本章中,我們會涉及到與 Android 安全相關的其他主題,這些主題不直接屬於已經涉及的任何主題。
6.1 Android 簽名過程
Android 應用程序以 Android 應用包文件(.apk
文件)的形式分發到設備上。 由於這個平臺的程序主要是用 Java 編寫的,所以這種格式與 Java 包的格式 -- jar
(Java Archive)有很多共同點,它用於將代碼,資源和元數據(來自可選的META-INF
目錄 )文件使用 zip 歸檔算法轉換成一個文件。 META-INF
目錄存儲軟件包和擴展配置數據,包括安全性,版本控制,擴展和服務[5]。 基本上,在 Android 的情況中,apkbuilder
工具將構建的項目文件壓縮到一起[1],使用標準的 Java 工具jarsigner
對這個歸檔文件簽名[6]。 在應用程序簽名過程中,jarsigner
創建META-INF
目錄,在 Android 中通常包含以下文件:清單文件(MANIFEST.MF
),簽名文件(擴展名爲.SF
)和簽名塊文件(.RSA
或.DSA
) 。
清單文件(MANIFEST.MF
)由主屬性部分和每個條目屬性組成,每個包含在未簽名的apk
中文件擁有一個條目。 這些每個條目中的屬性存儲文件名稱信息,以及使用 base64 格式編碼的文件內容摘要。 在 Android 上,SHA1 算法用於計算摘要。 清單 6.1 中提供了清單文件的摘錄。
1 Manifest−Version : 1.0
2 Created−By: 1.6.0 41 (Sun Microsystems Inc. )
3
4 Name: res/layout/main . xml
5 SHA1−Digest : NJ1YLN3mBEKTPibVXbFO8eRCAr8=
6
7 Name: AndroidManifest . xml
8 SHA1−Digest : wBoSXxhOQ2LR/pJY7Bczu1sWLy4=
複製代碼
代碼 6.1:清單文件的摘錄
包含被簽名數據的簽名文件(.SF
)的內容類似於MANIFEST.MF
的內容。 這個文件的一個例子如清單 6.2 所示。 主要部分包含清單文件的主要屬性的摘要(SHA1-Digest-Manifest-Main-Attributes
)和內容摘要(SHA1-Digest-Manifest
)。 每個條目包含清單文件中的條目的摘要以及相應的文件名。
1 Signature−Version : 1.0
2 SHA1−Digest−Manifest−Main−Attributes : nl/DtR972nRpjey6ocvNKvmjvw8=
3 Created−By: 1.6.0 41 (Sun Microsystems Inc. )
4 SHA1−Digest−Manifest : Ej5guqx3DYaOLOm3Kh89ddgEJW4=
5
6 Name: res/layout/main.xml
7 SHA1−Digest : Z871jZHrhRKHDaGf2K4p4fKgztk=
8
9 Name: AndroidManifest.xml
10 SHA1−Digest : hQtlGk+tKFLSXufjNaTwd9qd4Cw=
11 ...
複製代碼
代碼 6.2:簽名文件的摘錄
最後一部分是簽名塊文件(.DSA
或.RSA
)。 這個二進制文件包含簽名文件的簽名版本; 它與相應的.SF
文件具有相同的名稱。 根據所使用的算法(RSA 或 DSA),它有不同的擴展名。
相同的apk文件有可能簽署幾個不同的證書。 在這種情況下,在META-INF
目錄中將有幾個.SF
和.DSA
或.RSA
文件(它們的數量將等於應用程序簽名的次數)。
6.1.1 Android 中的應用簽名檢查
大多數 Android 應用程序都使用開發人員簽名的證書(注意 Android 的“證書”和“簽名”可以互換使用)。 此證書用於確保原始應用程序的代碼及其更新來自同一位置,並在同一開發人員的應用程序之間建立信任關係。 爲了執行這個檢查,Android 只是比較證書的二進制表示,它用於簽署一個應用程序及其更新(第一種情況)和協作應用程序(第二種情況)。
這種對證書的檢查通過PackageManagerService
中的方法int compareSignatures(Signature[] s1,Signature[] s2)
來實現,代碼如清單 6.3 所示。在上一節中,我們注意到在 Android 中,可以使用多個不同的證書籤署相同的應用程序。這解釋了爲什麼該方法使用兩個簽名數組作爲參數。儘管該方法在 Android 安全規定中佔有重要地位,但其行爲強烈依賴於平臺的版本。在較新版本中(從 Android 2.2 開始),此方法比較兩個Signature
數組,如果兩個數組不等於null
,並且如果所有s2
簽名都包含在s1
中,則返回SIGNATURE MATCH
值,否則爲SIGNATURE_NOT_MATCH
。在版本 2.2 之前,此方法檢查數組s1
是否包含在s2
中。這種行爲允許系統安裝升級,即使它們已經使用原始應用程序的證書子集簽名[2]。
在幾種情況下,需要同一開發人員的應用程序之間的信任關係。 第一種情況與signature
和signatureOrSystem
的權限相關。 要使用受這些權限保護的功能,聲明權限和請求它的包必須使用同一組證書籤名。 第二種情況與 Android 運行具有相同 UID 或甚至在相同 Linux 進程中運行不同應用程序的能力有關。 在這種情況下,請求此類行爲的應用程序必須使用相同的簽名進行簽名。
1 static int compareSignatures ( Signature[] s1 , Signature[] s2 ) {
2 if ( s1 == null ) {
3 return s2 == null
4 ? PackageManager.SIGNATURE_NEITHER_SIGNED
5 : PackageManager.SIGNATURE_FIRST_NOT_SIGNED;
6 }
7 if ( s2 == null ) {
8 return PackageManager.SIGNATURE_SECOND_NOT_SIGNED;
9 }
10 HashSet<Signature> set1 = new HashSet<Signature>() ;
11 for ( Signature sig : s1 ) {
12 set1.add( sig ) ;
13 }
14 HashSet<Signature> set2 = new HashSet<Signature>() ;
15 for ( Signature sig : s2 ) {
16 set2.add( sig ) ;
17 }
18 // Make sure s2 contains all signatures in s1 .
19 if ( set1.equals ( set2 ) ) {
20 return PackageManager.SIGNATURE_MATCH;
21 }
22 return PackageManager.SIGNATURE_NO_MATCH;
23 }複製代碼
代碼 6.3:PackageManagerService
中的compareSignatures
方法