Skip to content

Most visited

Recently visited

navigation

システム パーミッション

デザイン パターン

パーミッション

動画

Google I/O 2015 - Android M パーミッション:デベロッパー向けのベストプラクティス

Android は特権分離されたオペレーティング システムであり、各アプリは個別のシステム ID(Linux ユーザー ID とグループ ID)で動作します。システムの各部も、個々の ID で分割されています。Linux ではアプリをシステムから分離させ、アプリ同士も独立させています。

さらに、ある特定のプロセスを実行する具体的な操作に対して制限を設ける「パーミッション」構造や、特定のデータへのアドホック アクセスを許可する URI 単位のパーミッションなど、きめ細かいセキュリティ機能が提供されています。

このドキュメントでは、アプリケーション デベロッパー向けに Android が提供するセキュリティ機能を利用する方法を説明します。より一般的な Android セキュリティの概要 は、Android オープンソース プロジェクトでご覧いただけます。

セキュリティ アーキテクチャ

Android セキュリティ アーキテクチャ の設計において重要なのは、デフォルトで、すべてのアプリが他のアプリや OS、ユーザーに悪影響を及ぼすような操作を行うためのパーミッションを持たないようにすることです。この操作には、ユーザーの個人情報(連絡先や E メール情報)や他のアプリケーション ファイルの読み取りまたは書き込み、ネットワーク アクセス、端末のスリープモードへの移行抑止などが含まれます。

Android アプリは、それぞれプロセス サンドボックス内で動作するため、リソースやデータを明示的に共有しなければなりません。具体的には、ベーシック サンドボックスでは提供されない追加機能が必要な場合は、パーミッションを宣言します。アプリで必要なパーミッションを静的に宣言すると、Android システムがユーザーに同意を求めます。

アプリケーション サンドボックスはアプリ作成に使用されたテクノロジーに依存しません。特に Dalvik VM はセキュリティ バウンダリではありません。そのため、どんなアプリもネイティブ コードを実行できます(the Android NDK をご参照ください)。あらゆるタイプのアプリケーション(Java、native、hybrid など)が同じようにサンドボックス化され、同等のセキュリティが確保されます。

アプリケーションへの署名

すべての APK(.apk ファイル)は証明書で署名する必要があり、この証明書の秘密鍵はデベロッパーが保有します。証明書はアプリの製作者を識別します。証明書は認証局によって署名される必要はなく、Android アプリは自己署名証明書で問題なく署名できます。Android における証明書の目的は、アプリの作成者を識別することです。これにより、アプリに署名レベルのパーミッションのアクセス権を付与または拒否できます。またアプリの、別アプリと同じ Linux ID の付与を求めるリクエストを許可または拒否できます。

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

インストールの際、Android は個別の Linux ユーザー ID をパッケージごとに付与します。この ID は端末上にパッケージがある間は変わりません。別の端末上では、同じパッケージでも別の UID を持つ可能性があります。重要なのは、端末においてパッケージごとに個別の UID が付与されることです。

その理由は、セキュリティがプロセス レベルで適用されるためです。通常は 2 つのパッケージ コードを同じプロセス内で走らせることはできず、別の Linux ユーザーとして走らせる必要があるからです。AndroidManifest.xml 内のパッケージごとの manifest タグで sharedUserId 属性を使用すれば、複数パッケージに同じユーザー ID をアサインできます。その結果、セキュリティ上 2 つのパッケージを、同じのユーザー ID とファイル パーミッションを持つ同一のアプリとして扱うことができます。セキュリティを保つため、同じ署名のアプリに同じユーザー ID が付与される( sharedUserId をリクエストできる)のは 2 つまでという点に注意してください。

アプリで保存したデータにはすべて、そのアプリのユーザー ID が付与され、他のパッケージからは通常アクセスできません。getSharedPreferences(String, int)openFileOutput(String, int)openOrCreateDatabase(String, int, SQLiteDatabase.CursorFactory) を使用してファイルを新規作成する場合には、MODE_WORLD_READABLEMODE_WORLD_WRITEABLE フラグを使って、他のパッケージからファイルの読み取りや書き込みができるようにしてください。これらのフラグを設定した場合、ファイルの所有権は依然としてアプリ側にありますが、読み取りや書き込みのグローバル パーミッションが適切に付与されるため、他のどのアプリからもファイルを確認できるようになります。

パーミッションの使用

基本的に Android アプリは、デフォルトでは何もパーミッションがありません。つまり、ユーザー エクスペリエンスや端末上のデータに悪影響を及ぼす可能性のあることは何一つできないということです。端末の保護機能を最大限利用するには、<uses-permission> タグを 1 つ以上自身のアプリ マニフェストに含める必要があります。

たとえば、SMS 受信メッセージをモニターする必要があるアプリなら、次のように指定します。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.android.app.myapp" >
    <uses-permission android:name="android.permission.RECEIVE_SMS" />
    ...
</manifest>

アプリのマニフェスト内に Normal パーミッション(ユーザーの個人情報や端末操作へのリスクが少ないパーミッション)を記述した場合、システムは自動的にパーミッションを付与します。アプリのマニフェスト内に Dangerous パーミッション(ユーザーの個人情報や端末の通常の操作に影響を及ぼす可能性があるパーミッション)を記述した場合、システムはユーザーに対してパーミッションを明示的に許可するかを確認します。このユーザーへのリクエスト方法は、Android のシステム バージョンと、アプリが対象とするシステムバージョンによって異なります。

パーミッションの付与に失敗した場合には、 SecurityException がアプリにスローされることがほとんどですが、どのような場合でもそうなるとは限りません。たとえば、sendBroadcast(Intent) メソッドは、データが受信者に届くときにパーミッションを確認しますが、メソッド呼び出しが返されてからなので、パーミッションが失敗した場合は例外を捕捉できません。ただ、ほとんどの場合、パーミッションの失敗はシステムログに出力されます。

Android システムが提供するパーミッションは、Manifest.permission で確認できます。どのアプリも独自のパーミッションを定義して実行する可能性があるため、これが全パーミッションを網羅したリストというわけではありません。

以下のように、プログラムの実行中に特定のパーミッションが強制的に適用される場面も多くあります。

パーミッションの自動補正

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

例として、共有ストレージ領域へのアクセスを制限するために、WRITE_EXTERNAL_STORAGE のパーミッションが API レベル 4 で追加されました。もし targetSdkVersion が 3 以下であれば、このパーミッションは Android の新バージョン上でアプリに追加されます。

警告: アプリに自動的にパーミッションが追加された場合、実際には必要なかったとしても、Google Play のアプリ情報には追加のパーミッションが表示されます。

こうした状況を避け、不要なデフォルト パーミッションを削除するには、お使いの targetSdkVersion を常に最新にアップデートしておくことをお勧めします。各リリースで追加されたパーミッションは、Build.VERSION_CODES ドキュメントでご覧いただけます。

Normal パーミッションと Dangerous パーミッション

システム パーミッションは複数の保護レベルに分けられます。特に重要な保護レベルは、Normal および Dangerous パーミッションの 2 つです。

パーミッション グループ

Android システムのすべての Dangerous パーミッションは、パーミッション グループに帰属します。Android 6.0(API レベル 23)の端末、かつアプリの targetSdkVersion が 23 以降の場合、アプリが Dangerous パーミッションをリクエストしたときのシステム動作は次の通りです。

Normal パーミッションや自身のアプリで定義したパーミッションも含め、すべてのパーミッションがパーミッション グループに属することができます。ただし、パーミッション グループがユーザー エクスペリエンスに影響するのは、Dangerous パーミッションの場合のみです。Normal パーミッションについては、パーミッション グループを気にする必要はありません。

Android 5.1(API レベル 22)以前の端末、あるいはアプリの targetSdkVersion が 22 以前の場合、ユーザーはインストール時にパーミッションの付与を求められます。繰り返しになりますが、ユーザーには個別のパーミッションではなく、どのパーミッション グループがアプリに必要かが伝えられます。

表 1. Dangerous パーミッションとパーミッション グループ

パーミッション グループ パーミッション
CALENDAR
CAMERA
CONTACTS
LOCATION
MICROPHONE
PHONE
SENSORS
SMS
STORAGE

パーミッションの定義と適用

独自のパーミッションを適用するには、まず 1 つ以上の <permission> 要素を使用して AndroidManifest.xml 内に宣言をする必要があります。

たとえばアプリで、あるアクティビティを開始できるものを制御したい場合、次のようにパーミッションを宣言します。

<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)や 1 つのパーミッションの詳細情報(android:description)を閲覧するときに表示されます。ラベルは短くして、パーミッションが保護する主要な機能を短い言葉で説明します。説明には、パーミッションを付与すると何が許可されるのかを簡潔に記載してください。慣習としては 2 文で説明します。最初の文にはパーミッションを記載し、2 文目でパーミッションが許可されたときに問題が生じやすいポイントについて警告します。

以下は CALL_PHONE パーミッションのラベルと説明の例です。

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

設定アプリ、またはシェルコマンド adb shell pm list permissions を使って現在システムに定義されているパーミッションをご覧いただけます。設定アプリを使う場合は、[Settings] > [Applications] からご確認ください。アプリを選択して下にスクロールすると、使用中のパーミッションを確認できます。デベロッパーの方は 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

...

カスタム パーミッションの推奨

アプリは<uses-permission> 要素を定義することで、独自のカスタム パーミッションを定義したり、他のアプリのカスタム パーミッションをリクエストしたりすることが可能です。ただし、カスタム パーミッションが自身のアプリに必要かどうか、慎重に検討するようにしてください。

AndroidManifest.xml でパーミッションを適用

AndroidManifest.xml によって、システムやアプリの全コンポーネントに対するアクセスを制限するハイレベルなパーミッションを適用できます。そのためには、希望するコンポーネントに android:permission 属性を含め、アクセスを制御するパーミッション名を指定します。

Activity パーミッション(<activity> タグに適用)は、関連するアクティビティの呼び出しを制限します。パーミッションの確認は Context.startActivity() および Activity.startActivityForResult() で行われます。呼び出し元が必要なパーミッションを持たない場合は、SecurityException がスローされます。

Service パーミッション(<service> タグに適用)は、関連サービスの開始とバインドを制限します。パーミッションの確認は Context.startService()Context.stopService()Context.bindService() で行われます。呼び出し元が必要なパーミッションを持たない場合は、SecurityException がスローされます。

BroadcastReceiver パーミッション(<receiver> タグに適用)は、関連するレシーバーに対するブロードキャストの送信元を制限します。システムは送信されたブロードキャストを指定のレシーバーに届けるため、Context.sendBroadcast() が返された後にパーミッションを確認します。結果として、パーミッションが失敗すると送信元に例外がスローされないため、単にインテントが届かない状態になります。同様に、パーミッションは Context.registerReceiver() に付与され、プログラムで登録済みのレシーバーに対するブロードキャストの送信元を制限します。逆の見方をすると、Context.sendBroadcast() を呼び出してパーミッションを付与し、ブロードキャストを受信できるブロードキャスト レシーバー オブジェクトを制限します(以下を参照してください)。

ContentProvider パーミッション( <provider> タグに適用)は、ContentProvider のデータへのアクセスを制限します。(コンテンツ プロバイダには、あとに述べる URI パーミッションと呼ばれる追加のセキュリティ機能を使用できます)。他のコンポーネントと違い、2 つのパーミッション属性を個別に設定できます。android:readPermission はプロバイダからの情報を読み取りを、android:writePermission は書き込みを制限します。プロバイダが読み取りと書き込み両方のパーミッションで保護されている場合、書き込みのパーミッションを持っているだけでは、プロバイダの情報を読み取れません。パーミッションが確認されるのは、最初にプロバイダを取得するときと(どちらのパーミッションも持っていない場合には、SecurityException がスローされます)、プロバイダで操作を実行するときです。ContentResolver.query() を使うには、読み取りパーミッションが必要です。 ContentResolver.insert()ContentResolver.update()ContentResolver.delete() を使うには、書き込みパーミッションが必要です。すべてのケースにおいて、必要なパーミッションを持たない場合には SecurityException がスローされます。

ブロードキャスト送信時のパーミッションの適用

登録された BroadcastReceiver に対するインテントの送信元を制限するパーミッション(前述)に加えて、ブロードキャストを送信する時点で必要なパーミッションを指定することもできます。パーミッション文字列を使用して Context.sendBroadcast() を呼び出し、受信側のアプリにブロードキャストを受信するためのパーミッションが必要なことを伝えます。

受信側と送信側の両方がパーミッションを要求できる点に注目してください。この場合、インテントがターゲットに届くためには、両方のパーミッション チェックを通過する必要があります。

その他のパーミッションの適用

サービスを呼び出すときに、任意の細かいパーミッションを適用できます。そのためには、Context.checkCallingPermission() メソッドを使用します。期待するパーミッション文字列で呼び出すと、実行中の呼び出しプロセスにパーミッションが許可されたかどうかを示す整数が返されます。この方法は、サービスが公開している IDL インターフェース経由など、他のプロセスから呼び出そうとする場合にのみ使用できる点に注意してください。

他にも便利なパーミッションの確認方法がたくさんあります。その他のプロセスの PID がわかっている場合は、Context メソッド Context.checkPermission(String, int, int) を使ってその PID に対するパーミッションを確認できます。その他のアプリのパッケージ名がわかっている場合は、直接 PackageManager メソッド PackageManager.checkPermission(String, String) を使うと、特定のパッケージにパーミッションが付与されたかを確認できます。

URI パーミッション

これまでに説明した標準的なパーミッション システムは、コンテンツ プロバイダで使うには必ずしも十分なものとは言えません。コンテンツ プロバイダが読み取りと書き込みのパーミッションで自身を保護しようとしている一方、そのクライアントは特定の URI を他のアプリに渡して処理を実行できるようにしなければなりません。その典型的な例がメールアプリの添付ファイルです。メールには機密性の高いユーザーの個人情報が含まれているため、メールへのアクセスはパーミッションで保護されなければなりません。しかし、イメージ ビューアは添付の画像ファイルに対する URI を与えられても、添付ファイルを開くパーミッションは付与されてません。すべての E メールにアクセスするパーミッションを持つ理由がないからです。

この問題に対するソリューションは、URI 単位のパーミッションです。アクティビティの開始時またはアクティビティに結果を返すときに、呼び出し元は Intent.FLAG_GRANT_READ_URI_PERMISSIONIntent.FLAG_GRANT_WRITE_URI_PERMISSION を指定できます。これにより、インテント内の特定のデータ URI にアクセスするパーミッションが受信側のアクティビティに付与されます。そのインテントに相当するコンテンツ プロバイダのデータにアクセスするパーミッションがあるかどうかは問いません。

この仕組みによって共通の機能スタイルモデルが実現され、添付ファイルの開封やリストからの連絡先選択などのユーザー操作に対し、目的別の詳細なパーミッションを付与できるようになりました。これは、アプリに必要なパーミッションを、アプリの動作に直接関連するものだけに制限する上で非常に重要です。

詳細な URI パーミッションを付与するには、URI を保持するコンテンツ プロバイダとの連携が必要になります。よって、コンテンツ プロバイダでこの機構を実装し、android:grantUriPermissions 属性や <grant-uri-permissions> タグでサポートしていることを宣言することを強くお勧めします。

詳細情報はContext.grantUriPermission()Context.revokeUriPermission()Context.checkUriPermission() メソッドをご覧ください。

こちらもご覧ください。

機能要件を暗示するパーミッション
パーミッションをリクエストすることで、対応するハードウェアやソフトウェア機能を備えた端末に、アプリが暗黙的に限定される点について説明しています。
<uses-permission>
アプリに必要なシステム パーミッションを宣言する、マニフェスト タグに関する API リファレンスです。
Manifest.permission
すべてのシステム パーミッション用の API リファレンス

関連ドキュメント

端末の互換性
さまざまなタイプの端末での Android の動作と、端末ごとにアプリを最適化したり、別の端末でのアプリの利用を制限したりする方法について説明しています。
Android セキュリティの概要
Android プラットフォームのセキュリティ モデルに関する詳しい説明です。
This site uses cookies to store your preferences for site-specific language and display options.

Get the latest Android developer news and tips that will help you find success on Google Play.

* Required Fields

Hooray!

Follow Google Developers on WeChat

Browse this site in ?

You requested a page in , but your language preference for this site is .

Would you like to change your language preference and browse this site in ? If you want to change your language preference later, use the language menu at the bottom of each page.

This class requires API level or higher

This doc is hidden because your selected API level for the documentation is . You can change the documentation API level with the selector above the left navigation.

For more information about specifying the API level your app requires, read Supporting Different Platform Versions.

Take a short survey?
Help us improve the Android developer experience.
(Sep 2017 survey)