Android App Sandbox
在上一篇部落格,我們知道 Linux 中的 Sandbox 主要做隔離工作,將不同任務或使用者間的耦合降到最低。Android 應用也借用了 Linux Sandbox技術,將不同 APP 之間做了隔離;APP 之間的隔離主要是資源隔離和許可權訪問隔離。
1 2 3 4 5 6 7 |
<div style="max-width:600px;margin:0 auto;"> <div style="overflow:hidden;width:100%;display:block;"> <a href="/album/2015/2015-02-11-Understanding-security-on-Android-1.jpg"> <img style="display:block;float:left;max-width:300px;width:50%;position:relative;" src="/album/2015/2015-02-11-Understanding-security-on-Android-1.jpg" alt="Two Android applications, each on its own basic sandbox or process."/></a> </div> </div> |
如上圖所示,每個 Android APP 都執行在他們自己的 Linux 執行緒中(UID不同),每個應用程式彼此獨立,預設情況下無法訪問其他應用程式資源。 APP 許可權機制為應用程式之間的資源互訪提供了可行性,APP必須申請到許可權並經過使用者授權後才能訪問 Android 系統 API 或 其他陰功程式的服務。
如果兩個 Android App 執行在同一個程式裡(此時的 UID 是相同的),可以共享資料和程式碼。
那麼問題來了,如何讓兩個 APP 執行在同一個程式裡?
- 首先,兩個 APP 要用相同的 private key 來簽名
- 然後,新增兩個APP manifest.xml 檔案中屬性 android:sharedUserId,均設定為相同的值或名字(其實是設定成相同的UID)。
Android Permission 機制
Permissions 機制限制應用訪問特定的資源,如照相機、網路、外部儲存、檢視通話記錄以及某些API。
Android 定義了很多 Permissions,詳細可以參照官方文件。
若要申請某個許可權,可以在 manifest.xml 中新增 <user-permission>
屬性。
<uses-permission android:name="string" />
android:name 代表的就是許可權名稱。
自定義 Permission
APP 可以自己定義 Permission 來限制別的APP訪問自己的資源。別的應用想訪問此 APP 的資源,必須在自己的 AndroidManifest.xml 中新增此 Permission。自定義許可權也是在 AndroidManifest.xml 通過 <permission>
標籤定義。
下面我們來舉例說明。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<manifest xmlns:android="htttp://schemas.android.com/qpk/res/android" package="com.stackvoid.xxx" > <permission xmlns:android="http://schemas.android.com/apk/res/android" android:name="com.stackvoid.android.ACCESS_PRIVATE_DATA_TEST" android:description="@string/permission_description" android:label="@string/permission_label" android:protectionLevel="dangerous" android:permissionGroup="android.permission-group.PERSONAL_INFO" > </permission> </manifest> |
自定義一個 Permission,至少需要的元素是 name, description, label 和 protectionLevel。
以上 XML 語句定義了一個屬於 com.stackvoid.xxx 包的新許可權 – ACCESS_PRIVATE_DATA_TEST,這就意味著使用者如果授予另外一個程式 ACCESS_PRIVATE_DATA_TEST 許可權,所有通過 xxx 應用產生的資料都可以被那個應用程式讀取到。這裡,我們將 protectionLevel 設定為 dangerous,PERSONAL_INFO 定義在 android.permission-group 包中,表示 ACCESS_PRIVATE_DATA_TEST 屬於 PERSONAL_INFO 這一組。
這裡我們最關心的選項是 protectionLevel。
- normal,預設值。系統自動授予此 Permission,在 APP 安裝的時候能看到申請此 Permission。
- signature,具有相同的 Signature的 APP,才能申請此 Permission,否則,系統拒絕。
- dangerous,一般來說系統不會自動授予此 Permission,因為此 Permission 會有潛在的威脅;一般來說在使用 APP 的過程中,需要用到此許可權,會彈出視窗,讓使用者來授權。
當自定義許可權時,一定要遵循最小許可權原則,在這個例子中,所定義的許可權僅僅是外部應用可以讀取到資料,但是寫資料,必須定義另外一個許可權。
例項
首先建立了兩個 APP,APP A ,APP B ; APP A 自定義許可權,並且定義一個靜態廣播;APP B 使用此許可權來傳送廣播給 A。
APP A 的 AndroidManifest.xml 檔案如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.stackvoid.testbutton" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="19" /> <!-- 宣告許可權 --> <permission xmlns:android="http://schemas.android.com/apk/res/android" android:name="com.stackvoid.android.ACCESS_PRIVATE_DATA_TEST" android:description="@string/permission_description" android:label="@string/permission_label" android:permissionGroup="android.permission-group.PERSONAL_INFO" > </permission> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" launcheMode="singleTask" android:theme="@style/android:style/Theme.NoTitleBar.Fullscreen" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <!-- 註冊 Broadcast Receiver,並指定了給當前 Receiver 傳送訊息方需要的許可權 --> <receiver android:name="com.stackvoid.testbutton.TestButtonReceiver" android:permission="com.stackvoid.android.ACCESS_PRIVATE_DATA_TEST" > <intent-filter> <action android:name="com.stackvoid.test.action" /> </intent-filter> </receiver> </application> </manifest> |
APP B 的 AndroidManifest.xml 檔案如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.stackvoid.testsender" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="19" /> <!-- 宣告使用指定的許可權 --> <uses-permission android:name="com.stackvoid.android.ACCESS_PRIVATE_DATA_TEST" /> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/title_activity_main" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest> |
如上 Demo, APP B 給 APP A 傳送訊息,因為 APP B 中使用了 A 的許可權,A 可以收到了;若未在 APP B 的 AndroidManifest.xml 檔案中宣告使用 A 中自定義的許可權,APP B傳送的訊息,A是收不到的,因為 A 中的廣播需要相應的許可權。
另外,也可在 APP B 的 AndroidManifest.xml 檔案中宣告許可權時,新增android:protectionLevel=“signature”,指定 APP B只能接收到使用同一證照籤名的 APP 傳送的訊息。