定義自訂應用程式權限

Stay organized with collections Save and categorize content based on your preferences.

本文說明應用程式開發人員如何使用 Android 提供的安全性功能來定義自己的權限。定義自訂權限後,應用程式就能與其他應用程式共用資源和功能。如要進一步瞭解權限,請參閱權限總覽

背景

Android 是一種權限分離的作業系統,每個應用程式會以不同的系統身分(Linux 使用者 ID 及群組 ID)執行。系統的各個部分也分為不同的身分。 Linux 因而可以將各個應用程式隔離,並與系統隔離。

應用程式可以定義權限,讓其他應用程式可以提出要求使用其功能。也可以定義一些權限,自動讓任何其他應用程式以相同的憑證簽名,供應用程式使用。

應用程式簽署

所有的 APK 都必須使用由開發人員持有的私密金鑰的憑證簽名。憑證需要經過憑證授權單位簽署;在 Android 應用程式中使用自行簽署的憑證是完全沒問題也是最典型的做法。Android 中的憑證是用來辨別應用程式的作者。如此一來,系統就能對簽名級別權限核准或拒絕應用程式存取,以及核准或拒絕應用程式想要如同其他應用程式要求獲得相同的 Linux 身分

在裝置製造時間之後授予簽章權限

從 Android 12 開始,您可以在宣告時期利用簽章層級權限的knownCerts屬性,指定已知的簽署憑證的摘要。

您的應用程式可以宣告 knownCerts 屬性,針對特定簽署層級的權限,使用 protectionLevel 屬性中的 knownSigner 旗標。當應用程式這麼做時,如果提出要求的應用程式簽署歷程中的任何簽署者(包括目前的簽署者)符合 knownCerts 屬性中宣告權限的其中一個摘要,則系統便會將權限授予提出要求的應用程式。

knownSigner 旗標可以讓裝置和應用程式將簽章的權限授予其他應用程式,而不需在裝置製造和出貨時就簽署該應用程式。

使用者 ID 和檔案存取

在安裝時,Android 會為每個套件提供專屬的 Linux 使用者 ID。只要套件存在於該裝置,此身分都會保持不變。同一個套件在其他裝置上可能會有不同的 UID;不過重要的是,每個套件在其裝置上都有不同的 UID。

由於安全性的強制執行程序是在程序層級進行,因此任何兩個套件的程式碼,通常無法在同一程序中執行,因為這些套件必須以不同的 Linux 使用者身分執行。您可以在每個套件的 AndroidManifest.xml 資訊清單標記中使用 sharedUserId 屬性,將其指派為相同的使用者 ID。這麼一來,為了安全起見,系統會將兩個套件視為相同的應用程式,其具有相同的使用者 ID 和檔案權限。請注意,為了保障安全性,只有兩個具有相同簽章的應用程式(並要求相同的 sharedUserId)才會具有相同的使用者 ID。

應用程式儲存的所有資料將會被指定為與該應用程式相同的使用者 ID,而且通常其他套件不得存取。

若要進一步瞭解 Android 的安全模型,請參閱 Android 安全性總覽

定義及強制執行權限

若要強制執行自己的權限,您必須先在 AndroidManifest.xml 中使用一或多個 <permission> 元素進行宣告。

舉例來說,如果應用程式想要控管哪些人可以啟動其中一項活動,就可以按照以下方法為此作業宣告權限:

<manifest
  xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.example.myapp" >
    
    <permission
      android:name="com.example.myapp.permission.DEADLY_ACTIVITY"
      android:label="@string/permlab_deadlyActivity"
      android:description="@string/permdesc_deadlyActivity"
      android:permissionGroup="android.permission-group.COST_MONEY"
      android:protectionLevel="dangerous" />
    ...
</manifest>

注意事項:除非所有套件使用同一個憑證簽署,否則系統不允許多個套件以相同的名稱宣告一項權限。如果套件宣告了一項權限,系統將不允許使用者安裝具有相同權限名稱的其他套件,除非這些套件也使用與第一個套件相同的憑證簽署。為避免命名衝突,建議您使用反轉網域的方式為自訂權限命名,例如 com.example.myapp.ENGAGE_HYPERSPACE

protectionLevel 屬性為必要屬性,用來告知系統如何告知使用者應用程式需要權限,或是誰得以擁有該項權限,如連結文件中所述。

android:permissionGroup 屬性則為選擇性,僅用於協助系統向使用者顯示權限。在多數情況下,您應將此值設為標準系統群組(列在 android.Manifest.permission_group 中),不過您可以自行定義群組。建議使用現有群組,因為這樣可以簡化向使用者顯示的權限 UI。

您必須提供權限的標籤和說明。這些是字串資源,使用者可以在檢視權限清單 (android:label) 或單一權限 ({android:description) 的詳細內容時看到這些資源。 標籤應簡短;用幾個字來描述有關權限保護的重要功能說明。說明應為幾個句子,說明權限擁有者能夠執行的內容。我們的慣例是使用兩個句子:第一句用來說明權限,第二句則是警告使用者,在應用程式擁有權限時可能會出錯的問題類型。

以下是 CALL_PHONE 權限的標籤和說明範例:

<string name="permlab_callPhone">directly call phone numbers</string>
<string name="permdesc_callPhone">Allows the app to call
    phone numbers without your intervention. Malicious apps may
    cause unexpected calls on your phone bill. Note that this does not
    allow the app to call emergency numbers.</string>

建立權限群組

如上一節所示,您可以使用 android:permissionGroup 屬性來協助系統向使用者描述權限。在多數情況下,您應該將其設定為標準系統群組(列於 android.Manifest.permission_group),但您也可以使用 <permission-group> 定義自己的群組。

<permission-group> 元素會為一組權限定義一個標籤,這些內容在資訊清單中會透過 <permission> 元素宣告,也包括在其他地方宣告的項目。這只會影響權限在向使用者呈現時的分組方式。<permission-group> 元素不會指定屬於群組的權限,不過會為群組命名。

您可以在 <permission> 元素的 permissionGroup 屬性中指定群組名稱來為群組設定權限。

<permission-tree> 元素可用來宣告一個命名空間,供程式碼中定義的某一權限群組使用。

自訂權限建議

應用程式可以定義自己的自訂權限並 透過定義 <uses-permission> 元素要求其他應用程式自訂權限。不過,請務必審慎評估您的應用程式是否需要這麼做。

  • 如果要設計一套應用程式,讓應用程式可以顯示彼此的功能,請嘗試將應用程式設計為每個權限只需定義一次。如果應用程式並非使用相同的憑證簽署,您就必須這麼做。即使應用程式都使用相同的憑證簽署,最好的做法仍是每項權限只需定義一次。
  • 如果該項功能只有與提供功能的應用程式簽章相同的應用程式才能使用,您就可以藉由檢查簽章來省去定義自訂權限這項工作。當其中一個應用程式對另一個應用程式發出要求時,第二個應用程式可以先驗證兩個應用程式是否使用相同的憑證簽署,再符合該項要求。

繼續閱讀以下相關內容:

<uses-permission>
資訊清單標記的 API 參考資料,用於宣告應用程式所需的系統權限。

您可能也想瞭解以下主題:

Android 安全性總覽
針對 Android 平台安全性模型的詳細討論。