カスタムアプリ権限を定義する

このドキュメントでは、アプリ デベロッパーが Android のセキュリティ機能を使用して、独自の権限を定義する方法について説明します。カスタム権限を定義することで、アプリは他のアプリとリソースや機能を共有できます。権限の詳細については、権限の概要をご覧ください。

背景

Android は、権限が分離されたオペレーティング システムで、各アプリは個別のシステム ID(Linux ユーザー ID とグループ ID)で実行されます。システムの一部は、個別の ID にも分割されます。これにより、Linux はアプリ同士やシステム間でアプリを分離します。

アプリは他のアプリが要求できる権限を定義して、アプリの機能を他のアプリに対して公開できます。また、同じ証明書で署名された他のアプリで自動的に使用できるようになる権限も定義できます。

アプリ署名

APK はすべて、デベロッパーが秘密鍵を保持する証明書で署名する必要があります。証明書は認証局によって署名されている必要はありません。Android アプリでは通常、自己署名証明書を使用することが問題なく許可されます。Android における証明書の目的は、アプリの作成者を区別することです。これにより、システムはアプリに対して署名レベルの権限へのアクセスを許可または拒否し、別のアプリと同じ Linux ID の付与に関するリクエストを許可または拒否できます。

デバイス製造時以降に署名権限を付与する

Android 12(API レベル 31)以降、署名レベルの権限の knownCerts 属性を使用すると、宣言の際に既知の署名証明書のダイジェストを参照できます。

knownCerts 属性を宣言し、アプリにおける特定の署名レベルの権限の protectionLevel 属性で knownSigner フラグを使用できます。すると、現在の署名者を含むリクエスト元アプリの署名系列の署名者が、knownCerts 属性で権限とともに宣言されたダイジェストのいずれかに一致すると、システムはリクエスト元アプリに権限を付与します。

knownSigner フラグにより、デバイスとアプリはデバイス製造時と出荷時にアプリで署名することなく、署名権限を他のアプリに付与できます。

ユーザー ID とファイル アクセス

インストール時に、Android は各パッケージに個別の Linux ユーザー ID を付与します。ID はそのデバイスのパッケージの有効期間中は変わりません。別のデバイスでは、同じパッケージの UID が異なる場合があります。重要なのは、各パッケージが特定のデバイスで識別できる UID を持つことです。

セキュリティの適用はプロセスレベルで行われるため、2 つのパッケージのコードは通常、異なる Linux ユーザーとして実行する必要があることから、同じプロセスでは実行できません。

アプリによって保存されたデータには、そのアプリのユーザー ID が割り当てられ、通常は他のパッケージからはアクセスできません。

Android のセキュリティ モデルの詳細については、Android のセキュリティの概要をご覧ください。

権限を定義して適用する

独自の権限を適用するには、まず AndroidManifest.xml で 1 つ以上の <permission> 要素を使用して、その権限を宣言する必要があります。

命名規則

すべてのパッケージが同じ証明書を使用して署名されている場合を除き、複数のパッケージで同じ名前の権限を宣言することはできません。パッケージで権限を宣言すると、ユーザーは同じ権限名の他のパッケージをインストールできなくなります(他のパッケージが最初のパッケージと同じ証明書を使用して署名されている場合を除く)。

逆ドメイン形式の命名方法を使用して、権限の前にアプリのパッケージ名を接頭辞として付加し、続いて.permission.、その後に権限が表す機能の説明を大文字の SNAKE_CASE 形式で指定することをおすすめします。例としては「com.example.myapp.permission.ENGAGE_HYPERSPACE」のようになります。

このおすすめの方法を採用すると、名前の競合を回避し、カスタム権限の所有者と意図を明確に示すことができます。

たとえば、別のどのアプリがアクティビティの 1 つを開始できるかを制御する必要があるアプリでは、このオペレーションの権限を次のように宣言できます。

<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>

リンク先のドキュメントに記載されているように、権限が必要なアプリについてユーザーに通知する方法、どのアプリが権限を保持できるかについて、システムに指示する protectionLevel 属性が必要です。

android:permissionGroup 属性はオプションで、システムがユーザーに権限を表示できるようにするためにのみ使用されます。ほとんどの場合、標準のシステム グループ(android.Manifest.permission_group に記載)に設定しますが、次のセクションで説明しているとおり、自分でグループを定義することもできます。ユーザーに表示される権限 UI が簡略化されることから、既存のグループの使用をおすすめします。

権限のラベルと説明の両方を指定する必要があります。これらの文字列リソースは、ユーザーが権限のリスト(android:label)または、1 つの権限の詳細(android:description)を確認しているときに表示されます。ラベルは短くする必要があり、いくつかの単語を使用して権限が保護している重要な機能を説明するようにします。説明では数行で権限が所有者に実行を許可する内容を説明します。通常は 2 つの文で説明します。1 文目は権限について説明し、2 文目はアプリに権限が付与された場合に、発生する可能性があるエラーの種類についてユーザーに警告します。

以下に、CALL_PHONE 権限のラベルと説明の例を示します。

<string name="permlab_callPhone">directly call phone numbers</string>
<string name="permdesc_callPhone">Allows the app to call non-emergency
phone numbers without your intervention. Malicious apps may cause unexpected
calls on your phone bill.</string>

権限グループを作成する

前のセクションで説明したように、android:permissionGroup 属性を使用して、システムがユーザーに権限を説明するようにできます。ほとんどの場合、標準のシステム グループ(android.Manifest.permission_group に記載)に設定しますが、<permission-group> を使用して独自のグループを定義することもできます。

<permission-group> 要素は、権限セット(<permission> 要素を使用してマニフェストで宣言されている権限と他の場所で宣言されている権限の両方)のラベルを定義します。これは、ユーザーに表示された際の権限のグループ化方法にのみ影響します。<permission-group> 要素は、グループに属する権限を指定しませんが、グループに名前を付与します。

グループに権限を割り当てるには、グループ名を <permission> 要素の permissionGroup 属性に割り当てます。

<permission-tree> 要素は、コードで定義されている権限のグループの名前空間を宣言します。

カスタム権限についての推奨事項

<uses-permission> 要素を定義することで、独自のカスタム権限を定義でき、他のアプリのカスタム権限をリクエストできます。ただし、その必要があるかどうかは慎重に検討してください。

  • 互いに機能を公開する一連のアプリを設計する場合は、それぞれの権限が 1 回のみ定義されるようにアプリを設計してください。アプリがすべて同じ証明書で署名されていない場合は、このようにする必要があります。アプリがすべて同じ証明書で署名されていても、各権限を 1 回のみ定義することをおすすめします。
  • 機能が提供元アプリと同じ署名で署名されたアプリでのみ使用できる場合は、署名チェック機能を使用してカスタム権限を定義せずに済ませることができます。いずれかのアプリが別のアプリのリクエストを行うと、2 つ目のアプリはリクエストに応える前に両方のアプリが同じ証明書で署名されていることを確認できます。

カスタム権限が必要な場合は、権限チェックを行っているアプリと同じデベロッパーが署名したアプリのみがアクセスする必要があるかどうかを検討します。たとえば、同じデベロッパーによる 2 つのアプリ間でのプロセス間通信(IPC)の保護を実装する場合などが該当します。そのような場合は、署名権限の使用をおすすめします。署名権限はユーザーの同意を必要とせず、ユーザーの混乱を招く可能性がある、ユーザーによる承認が必要な権限を避けられます。

関連情報:

<uses-permission>
アプリに必要なシステム権限を宣言するマニフェスト タグの API リファレンス。

その他の情報:

Android のセキュリティの概要
Android プラットフォームのセキュリティ モデルに関する詳細な説明です。