機密データへのアクセスニーズを決定する

アクセス権限の目的は、Android ユーザーのプライバシーを保護することです。Android アプリは、ユーザーの機密データ(連絡先や SMS など)と特定のシステム機能(カメラやインターネットなど)へのアクセス権限をリクエストする必要があります。機能に応じて、システムはアクセス権限を自動的に付与するか、またはユーザーにリクエストの承認を求めます。

Android セキュリティ アーキテクチャの設計においては、いかなるアプリもデフォルトでは他のアプリ、オペレーティング システム、ユーザーに悪影響を及ぼす操作を行う権限を持たないようにすることが重要です。そうした操作には、ユーザーの個人情報(連絡先やメールアドレス)の読み取りまたは書き込み、他のアプリのファイルの読み取りまたは書き込み、ネットワークへのアクセス、デバイスのスリープモードへの移行の抑止などがあります。

このページでは、Android のアクセス権限の仕組みの概要を示します。具体的には、ユーザーに対する権限のプロンプト、インストール時と実行時の権限リクエストの違い、権限が適用される仕組み、権限の種類と権限グループなどについて説明します。アプリのアクセス権限を使用するためのハウツーガイドのみを参照したい場合は、アプリの権限をリクエストするをご覧ください。

権限の承認

アプリ マニフェスト <uses-permission> タグを挿入することにより、アプリが必要とする権限を公表する必要があります。たとえば、SMS メッセージを送信するアプリの場合、マニフェストに次の行を挿入します。

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
              package="com.example.snazzyapp">

        <uses-permission android:name="android.permission.SEND_SMS"/>

        <application ...>
            ...
        </application>
    </manifest>
    

アプリのマニフェストに標準の権限(つまり、ユーザーのプライバシーやデバイスの挙動にとってほとんど危険がない権限)がリストされた場合、システムは自動的にその権限をアプリに付与します。

上記の SEND_SMS 権限のような危険な権限(つまり、ユーザーのプライバシーまたはデバイスの通常の挙動に悪影響を及ぼす可能性がある権限)がアプリのマニフェストに含まれている場合、ユーザーはそうした権限の付与に明示的な同意を与えることを求められます。

標準の権限と危険な権限の詳細については、保護レベルをご覧ください。

危険な権限をリクエストするプロンプト

ユーザーの同意を必要とするのは、危険な権限のみです。Android がユーザーに危険な権限の付与をリクエストする方法は、ユーザーのデバイスで実行されている Android のバージョンと、アプリがターゲットとするシステムのバージョンによって異なります。

実行時リクエスト(Android 6.0 以上)

デバイスで Android 6.0(API レベル 23)以上を実行していて、かつ、アプリの targetSdkVersion が 23 以上である場合、ユーザーは、インストール時にはアプリの権限について通知されません。アプリは、実行時に危険な権限の付与をユーザーに求める必要があります。アプリが権限をリクエストすると、アプリがアクセスしようとしている権限グループを示すシステム ダイアログ(図 1 の左を参照)がユーザーに表示されます。ダイアログには、[許可しない] ボタンと [許可] ボタンがあります。

ユーザーが権限リクエストを拒否した場合、アプリが次に権限をリクエストすると、ダイアログにチェックボックスが表示されます。このチェックボックスをオンにすると、ユーザーはそれ以降権限の付与をリクエストされなくなります(図 1 の右を参照)。

図 1. 初回の権限ダイアログ(左)と、それ以降のリクエストをオフにできる 2 回目の権限ダイアログ(右)

ユーザーが [次回から表示しない] チェックボックスをオンにして [許可しない] をタップすると、その後アプリが同じ権限をリクエストしようとしても、システムはユーザーにプロンプトを表示しません。

アプリがリクエストした権限をユーザーがアプリに付与したとしても、アプリが常に権限を保持できるとは限りません。ユーザーは、システム設定で権限を個別に有効または無効にすることもできるからです。アプリ側では、実行時エラー(SecurityException)を防ぐため、実行時に必ず権限をチェックして、付与されていなければリクエストする必要があります。

実行時の権限リクエストの処理方法の詳細については、アプリの権限をリクエストするをご覧ください。

インストール時のリクエスト(Android 5.1.1 以下)

デバイスで Android 5.1.1(API レベル 22)以下を実行している場合、または Android の任意のバージョンを実行していてアプリの targetSdkVersion が 22 以下である場合、ユーザーはインストール時に、すべての危険な権限をアプリに付与するかどうかを自動的に尋ねられます(図 2 を参照)。

図 2. インストール時の権限ダイアログ

ユーザーが [同意する] をクリックすると、アプリがリクエストするすべての権限が付与されます。ユーザーが権限リクエストを拒否すると、システムはアプリのインストールをキャンセルします。

アプリのアップデートで追加の権限が必要になる場合、ユーザーはアプリをアップデートする前に、追加の新しい権限を承認するかどうかを尋ねられます。

権限をリクエストする際に推奨されるユーザー エクスペリエンスのパターンの概要については、アプリの権限に関するおすすめの設定をご覧ください。

ユーザーが付与する権限をチェックおよびリクエストする方法については、アプリの権限をリクエストするをご覧ください。

ユーザーの機密情報へのアクセスをリクエストするプロンプト

一部のアプリでは、通話ログや SMS メッセージに関するユーザーの機密情報にアクセスする必要があります。通話ログと SMS メッセージのための権限をリクエストし、アプリを Play ストアに公開する場合は、実行時に権限をリクエストする前に、アプリをコアシステム機能のデフォルト ハンドラとして設定することをユーザーに求める必要があります。

デフォルト ハンドラ プロンプトをユーザーに表示する方法のガイダンスを含むデフォルト ハンドラの詳細については、デフォルト ハンドラでのみ使用される権限に関するガイドをご覧ください。

オプションのハードウェア機能の権限

一部のハードウェア機能(Bluetooth やカメラなど)にアクセスするには、アプリの権限が必要です。ただし、実際には、こうしたハードウェア機能をすべての Android デバイスが備えているわけではありません。したがって、アプリが CAMERA 権限をリクエストする場合、マニフェストに <uses-feature> タグも挿入して、この機能が実際に必要かどうかを宣言することが重要です。例:

<uses-feature android:name="android.hardware.camera" android:required="false" />
    

機能に対して android:required="false" を宣言すると、Google Play は、その機能を持たないデバイスにアプリをインストールすることを許可します。次に、PackageManager.hasSystemFeature() を呼び出して実行時にデバイスがその機能を備えているかどうかをチェックし、備えていなければその機能を無効にする必要があります。

<uses-feature> タグを指定しなかった場合、アプリが該当する権限をリクエストしていることが Google Play によって確認されると、アプリはこの機能を必要としていると見なされます。したがって、<uses-feature> タグで android:required="true" を宣言したときと同様に、Google Play はその機能を持たないデバイスからアプリをフィルタリングします。

詳細については、Google Play と機能ベースのフィルタリングをご覧ください。

権限の適用

権限の目的はシステム機能を要求することだけではありません。アプリが提供するサービスでは、カスタム権限を適用して、サービスを使用できるユーザーを制限できます。カスタム権限の宣言の詳細については、カスタムアプリ権限の定義をご覧ください。

アクティビティ権限の適用

android:permission 属性によってマニフェスト内の <activity> タグに適用される権限は、その Activity を開始できる主体を制限します。権限は、Context.startActivity()Activity.startActivityForResult() の中でチェックされます。呼び出し元に必要な権限がない場合は、呼び出しから SecurityException がスローされます。

サービス権限の適用

android:permission 属性によってマニフェスト内の <service> タグに適用される権限は、関連する Service を開始またはバインドできる主体を制限します。権限は、Context.startService()Context.stopService()Context.bindService() の中でチェックされます。呼び出し元に必要な権限がない場合は、呼び出しから SecurityException がスローされます。

ブロードキャスト権限の適用

android:permission 属性によってマニフェスト内の <receiver> タグに適用される権限は、関連する BroadcastReceiver にブロードキャストを送信できる主体を制限します。システムは送信されたブロードキャストを指定されたレシーバに配信しようとするので、権限は Context.sendBroadcast() が返された後でチェックされます。したがって、権限エラーが発生しても、呼び出し元には例外がスローされません。単に Intent が配信されないだけです。

同様に、Context.registerReceiver() に権限を与えることにより、プログラムで登録されたレシーバにブロードキャストを送信できる主体を制限できます。逆に、Context.sendBroadcast() を呼び出す際に権限を与えて、ブロードキャストを受信できるブロードキャスト レシーバを制限することもできます。

ブロードキャストの受信側と送信側の両方で権限が必要とされる場合があります。その場合、関連するターゲットにインテントが配信されるためには、両方の権限チェックに合格する必要があります。詳細については、権限を使用してブロードキャストを制限するをご覧ください。

コンテンツ プロバイダ権限の適用

android:permission 属性によってマニフェスト内の <provider> タグに適用される権限は、ContentProvider のデータにアクセスできる主体を制限します(コンテンツ プロバイダでは、後述の URI 権限と呼ばれる追加のセキュリティ機能を使用できます)。他のコンポーネントと異なり、2 つの権限属性を個別に設定できます。android:readPermission はプロバイダから読み取りを行う主体を制限し、android:writePermission は書き込みを行う主体を制限します。プロバイダが読み取りと書き込みの両方の権限で保護されている場合、書き込み権限だけを持っていても、プロバイダの情報を読み取ることはできません。

権限がチェックされるのは、最初にプロバイダを取得するとき(いずれかの権限を持っていないと SecurityException がスローされます)と、プロバイダで操作を行うときです。ContentResolver.query() を使用するには、読み取り権限が必要です。ContentResolver.insert()ContentResolver.update()ContentResolver.delete() を使用するには、書き込み権限が必要です。上記のすべての場合において、必要な権限を持っていなければ、呼び出しから SecurityException がスローされます。

URI 権限

これまでに説明した標準的な権限システムは、コンテンツ プロバイダで使用するには不十分であることがままあります。コンテンツ プロバイダを読み取りおよび書き込み権限で保護する必要がある一方で、その直接のクライアントは特定の URI を他のアプリに渡して処理を行わなくてはなりません。

典型的な例は、メールアプリの添付ファイルです。メールは機密性の高いユーザーデータであるため、メールへのアクセスは権限で保護する必要があります。しかし、イメージ ビューアに画像添付ファイルの URI が与えられても、イメージ ビューアにはすべてのメールにアクセスする権限を保持する理由がないため、添付ファイルを開く権限がありません。

この問題の解決策が、URI ごとの権限です。アクティビティを開始するときまたはアクティビティに結果を返すときに、呼び出し元は Intent.FLAG_GRANT_READ_URI_PERMISSIONIntent.FLAG_GRANT_WRITE_URI_PERMISSION を設定できます。これにより、インテントに対応するコンテンツ プロバイダのデータにアクセスする権限の有無にかかわらず、インテント内の特定のデータ URI にアクセスする権限が受信側アクティビティに付与されます。

この仕組みによって、ユーザー操作(添付ファイルの開封や連絡先リストからの選択など)に対し臨機応変にきめ細かい権限を付与できる一般的な機能スタイルモデルが利用可能になります。この仕組みは、アプリが要求する権限を、アプリの動作に直接関連するものだけに制限するうえで非常に重要です。

アプリ内で他のアプリがアクションの責任を負う最も安全な実装を構築するには、この方法できめ細かい権限を使用し、android:grantUriPermissions 属性または <grant-uri-permissions> タグでアプリが権限をサポートすることを宣言する必要があります。

詳細については、Context.grantUriPermission()Context.revokeUriPermission()Context.checkUriPermission() の各メソッドの説明をご覧ください。

その他の権限の適用

サービスを呼び出すとき、任意のきめ細かい権限を適用できます。そのためには、Context.checkCallingPermission() メソッドを使用します。目的の権限文字列で呼び出しを行うと、実行中の呼び出しプロセスに権限が付与されたかどうかを示す整数値が返されます。この方法は、別のプロセスからの呼び出しを実行する場合にのみ使用できることに注意してください。これは、一般的にはサービスから発行された IDL インターフェースを介して行いますが、別のプロセスに固有の他の方法で行うこともあります。

有用な権限のチェック方法は他にもいくつかあります。別のプロセスのプロセス ID(PID)がわかっている場合は、Context.checkPermission() メソッドを使用してその PID に対する権限をチェックできます。別のアプリのパッケージ名がわかっている場合は、PackageManager.checkPermission() メソッドを使用してそのパッケージに特定の権限が付与されているかどうかを調べられます。

権限の自動補正

時間の経過に伴って、プラットフォームに新たな制約が追加されることがあります。たとえば、特定の API を使用するために、以前は不要だった権限をアプリがリクエストする必要が生じた場合などです。既存のアプリはそうした API に自由にアクセスできることを想定しているため、新しいプラットフォーム バージョンでアプリが失敗する(それによって新しい権限の対象からアプリを除外する)ことを避けるために、Android はアプリのマニフェストに新しい権限の付与リクエストを適用することがあります。Android は、アプリに権限が必要かどうかを targetSdkVersion 属性の値に基づいて判断します。権限が追加されたバージョンよりもこの値が小さければ、Android は権限を追加します。

たとえば、共有ストレージ領域へのアクセスを制限するために、最初は API レベル 19 で READ_EXTERNAL_STORAGE 権限が適用されたとします。アプリの targetSdkVersion が 18 以下であれば、Android の新しいバージョンで、この権限がアプリに追加されます。

注意: アプリに自動的に権限が追加された場合、実際にはアプリにその権限が不要だったとしても、Google Play のアプリ情報には追加された権限が表示されます。このような状況を避けて不要なデフォルトの権限を削除するには、 targetSdkVersion を常に最新の(最大の)値にアップデートしてください。各リリースで追加された権限は、Build.VERSION_CODES ドキュメントで確認できます。

保護レベル

権限はいくつかの保護レベルに分類されます。保護レベルは、実行時の権限リクエストが必要かどうかに影響します。

サードパーティのアプリに影響する権限の保護レベルは、標準、署名、危険の 3 つです。特定の権限の保護レベルを確認するには、権限 API リファレンスのページをご覧ください。

標準の権限

標準の権限に該当するのは、アプリがアプリのサンドボックス外のデータやリソースにアクセスする必要があるが、ユーザーのプライバシーや他のアプリの挙動に影響する危険がほとんどないケースです。たとえば、タイムゾーンを設定する権限は、標準の権限です。

アプリがマニフェストで標準の権限の必要性を宣言している場合、システムはインストール時にその権限を自動的にアプリに付与します。ユーザーは標準の権限を付与するかどうかを尋ねられることはなく、標準の権限を取り消すこともできません。

署名権限

システムはインストール時に署名権限をアプリに付与しますが、権限を使用するアプリが、権限を定義しているアプリと同じ証明書で署名されている場合に限られます。

危険な権限

危険な権限に該当するのは、アプリがユーザーの個人情報を含むデータやリソースを要求するケースや、ユーザーが保存したデータや他のアプリの挙動に影響を及ぼす可能性があるケースです。たとえば、ユーザーの連絡先を読み取る機能には危険な権限が必要です。アプリが危険な権限の必要性を宣言している場合、ユーザーは明示的にアプリに権限を付与することを求められます。ユーザーが権限を承認しない限り、アプリはその権限に依存する機能を提供できません。

アプリが危険な権限を使用するには、実行時に権限の付与をユーザーに求める必要があります。ユーザーにプロンプトを表示する方法の詳細については、危険な権限をリクエストするプロンプトをご覧ください。

特別な権限

標準の権限とも危険な権限とも異なる効果を持つ権限がいくつかあります。SYSTEM_ALERT_WINDOWWRITE_SETTINGS は特に取扱いに注意を要するため、ほとんどのアプリでは使用するべきではありません。これらの権限がアプリで必要な場合は、マニフェスト内で権限を宣言し、かつ、ユーザーの承認を求めるインテントを送信する必要があります。システムはインテントに対応するために、ユーザーに対して詳細な管理画面を表示します。

これらの権限をリクエストする方法の詳細については、SYSTEM_ALERT_WINDOW および WRITE_SETTINGS のリファレンスの該当項目をご覧ください。

Android システムが提供するすべての権限は、Manifest.permission で確認できます。

権限グループ

権限は、デバイスの機能に応じて、いくつかのグループに分けられています。このシステムの下で、権限リクエストはグループレベルで処理され、1 つの権限グループがアプリ マニフェスト内の複数の権限宣言に対応します。たとえば、SMS グループには、READ_SMSRECEIVE_SMS の両方の宣言が含まれています。権限をこのようにグループ化することにより、ユーザーは、複雑で専門的な権限リクエストに煩わされずに、十分な情報に基づいて適切な判断を下すことができます。

Android システムのすべての危険な権限は、なんらかの権限グループに属しています。すべての権限は、保護レベルと無関係に権限グループに所属できます。ただし、権限が属するグループがユーザー エクスペリエンスに影響するのは、危険な権限の場合だけです。

デバイスで Android 6.0(API レベル 23)を実行していて、アプリの targetSdkVersion が 23 以上である場合、アプリが危険な権限をリクエストしたときのシステムの動作は次のとおりです。

  • 現時点で、該当する権限グループ内の権限がアプリにない場合は、アプリがアクセスしようとしている権限グループを示す権限リクエスト ダイアログがユーザーに表示されます。ダイアログには、そのグループ内の具体的な権限は表示されません。たとえば、アプリが READ_CONTACTS 権限をリクエストした場合、ダイアログには、アプリがデバイスの連絡先にアクセスする必要があることだけが示されます。ユーザーが承認した場合は、リクエストされた権限だけがアプリに付与されます。
  • 同じ権限グループ内の別の危険な権限がすでにアプリに付与されている場合は、ユーザーへのプロンプトなしで直ちに権限がアプリに付与されます。たとえば、以前 READ_CONTACTS 権限をリクエストして付与されたアプリが WRITE_CONTACTS をリクエストした場合、ユーザーには権限リクエスト ダイアログが表示されず、直ちにその権限がアプリに付与されます。

注意: Android SDK の将来のバージョンでは、特定の権限が別のグループに移動される可能性があります。そのため、現行の権限グループの編成に基づいてアプリのロジックを作成することは避けてください。

たとえば、Android 8.1(API レベル 27)では、READ_CONTACTSWRITE_CONTACTS と同じ権限グループに属しています。アプリが READ_CONTACTS 権限をリクエストしてから WRITE_CONTACTS 権限をリクエストした場合、必ずしも WRITE_CONTACTS 権限が自動的に付与されるとは限りません。

デバイスで Android 5.1(API レベル 22)以下を実行しているか、アプリの targetSdkVersion が 22 以下である場合、ユーザーはインストール時に権限を付与するかどうかを尋ねられます。この場合も、システムは、個別の権限ではなくどの権限グループがアプリに必要かをユーザーに知らせます。たとえば、アプリが READ_CONTACTS をリクエストした場合、インストール ダイアログには連絡先グループが示されます。ユーザーが承認すると、READ_CONTACTS 権限だけがアプリに付与されます。

注: ユーザーが同じグループ内の別の権限をすでに付与している場合でも、アプリはすべての必要な権限を明示的にリクエストする必要があります。また、権限グループの編成については、今後の Android リリースで変更される可能性があります。アプリのコードでは、同じグループに属する特定の権限のセットに依存するロジックを使用しないようにしてください。

アプリの権限を表示する

システムで現在定義されているすべての権限を表示するには、設定アプリまたはシェルコマンド adb shell pm list permissions を使用します。設定アプリにアクセスするには、[設定] > [アプリ] に移動します。アプリを選択して下にスクロールすると、アプリが使用する権限を確認できます。デベロッパーの場合は、adb の '-s' オプションを使用して、ユーザーが目にするのと同様の形式で権限を表示できます。

    $ adb shell pm list permissions -s
    All Permissions:

    Network communication: view Wi-Fi state, create Bluetooth connections, full
    internet access, view network state

    Your location: access extra location provider commands, fine (GPS) location,
    mock location sources for testing, coarse (network-based) location

    Services that cost you money: send SMS messages, directly call phone numbers

    ...
    

また、adb の -g オプションを使用すると、エミュレータまたはテストデバイスにアプリをインストールする際に、すべての権限を自動的に付与できます。

    $ adb shell install -g MyApp.apk
    

その他のリソース