Android プラットフォームでは、アプリケーション リソースの識別と隔離のために Linux ユーザーベースの保護を利用しています。これにより、アプリが互いに隔離され、悪意のあるアプリからアプリやシステムが保護されます。これを行うために、Android は各 Android アプリに固有のユーザー ID(UID)を割り当て、独自のプロセスで実行します。
Android では、UID を使用してカーネルレベルのアプリ サンドボックスをセットアップします。カーネルは、アプリに割り当てられたユーザー ID やグループ ID といった標準的な Linux の機能を通して、アプリとシステムの間にプロセスレベルでセキュリティを提供します。デフォルトでは、アプリは相互にやり取りできず、OS へのアクセスが制限されています。アプリ A がアプリ B のデータを読み取ったり、許可なく電話をかけたりといった悪意のある動作をしようとしても、適切なデフォルトのユーザー権限がないため阻止されます。サンドボックスはシンプルで監査可能であり、数十年の実績を持つ UNIX 形式のユーザーごとのプロセス分離とファイル権限に基づいています。
アプリ サンドボックスはカーネル内にあるため、このセキュリティ モデルはネイティブ コードと OS アプリの両方にまで及びます。OS ライブラリ、アプリ フレームワーク、アプリ ランタイム、すべてのアプリなど、カーネル上にあるすべてのソフトウェアは、アプリ サンドボックス内で動作します。一部のプラットフォームでは、デベロッパーは特定の開発フレームワーク、API セット、言語に制約されることがあります。Android の場合、セキュリティを適用する必要があるアプリの記述方法に制限はありません。この点で、ネイティブ コードは解釈済みのコードと同じくらいサンドボックス化されています。
保護
通常、適切に構成されたデバイスのアプリ サンドボックスから抜け出すには、Linux カーネルのセキュリティを侵害する必要があります。ただし、他のセキュリティ機能と同様に、アプリ サンドボックスに適用される個々の保護も完璧ではないため、単一の脆弱性を突かれて OS や他のアプリが侵害されないようにするための多層防御が重要になります。
Android では数多くの保護機能を使用して、アプリ サンドボックスを強化しています。こうした保護機能は時間をかけて導入され、元からある UID ベースの任意アクセス制御(DAC)サンドボックスを大幅に強化してきました。以前の Android リリースには次の保護機能が含まれていました。
- Android 5.0 では、SELinux の強制アクセス制御(MAC)によるシステムとアプリの分離が導入されました。ただし、すべてのサードパーティ アプリが同じ SELinux コンテキスト内で実行されたため、アプリ間の分離は主に UID DAC によって行われました。
- Android 6.0 では、SELinux サンドボックスが拡張され、物理的なユーザーごとの境界を越えてアプリが分離されるようになりました。さらに、Android ではアプリデータの安全なデフォルト値も設定されています。
targetSdkVersion >= 24
のアプリでは、アプリのホーム ディレクトリのデフォルトの DAC 権限が 751 から 700 に変更されました。これにより、個人のアプリデータのデフォルトの安全性が向上しました(ただし、アプリはこのデフォルト値をオーバーライドできます)。 - Android 8.0 では、すべてのアプリが、アプリが使用を許可されたシステムコールを制限する
seccomp-bpf
フィルタを使用して実行するように設定され、アプリとカーネルの境界が強化されました。 - Android 9 では、
targetSdkVersion >= 28
のすべての非特権アプリが個々の SELinux サンドボックスで動作する必要があるため、アプリごとに MAC が提供されます。この保護機能により、アプリの分離状態が改善され、安全なデフォルト値がオーバーライドされることを防ぎ、アプリのデータに自由にアクセスできないようにします。 - Android 10 では、アプリに対してファイル システムの raw データのビューが制限されており、/sdcard/DCIM などのパスに直接アクセスできません。ただし、アプリは Context.getExternalFilesDir() などの適用可能なメソッドにより返されたパッケージ固有のパスに対しては、引き続き完全な raw アクセスを行うことができます。
ファイルの共有に関するガイドライン
どこからでもアプリデータにアクセスできるように設定することは、セキュリティ上おすすめできません。すべてのユーザーにアクセス権が付与されるため、目的の受信者のみにアクセスを制限することができません。この方法は、情報漏洩や Confused deputy(混乱した使節)の脆弱性につながり、機密性の高いデータを扱うアプリ(メール クライアントなど)を狙う不正なソフトウェアにとって格好の標的となります。Android 9 以降では、このような方法でファイルを共有することは targetSdkVersion>=28
のアプリでは明示的に禁止されています。
ファイルを共有する際には、どこからでもアプリデータにアクセスできるようにする代わりに、次のガイドラインを参考にしてください。
- アプリが別のアプリとファイルを共有する必要がある場合は、コンテンツ プロバイダを使用してください。コンテンツ プロバイダは適切な粒度でデータを共有しますが、どこからでもアクセス可能な UNIX 権限に付随する多くのマイナス面はありません(詳細については、コンテンツ プロバイダの基本をご覧ください)。
- どうしても外部に公開する必要のあるファイル(写真など)がアプリに存在する場合は、メディア固有の形式(写真、動画、音声ファイルのみ)にして、MediaStore クラスを使用して保存する必要があります(メディア アイテムを追加する方法について詳しくは、共有ストレージからメディア ファイルにアクセスするをご覧ください)。
ストレージの実行時の権限は、MediaStore を介して、強く型付けされたコレクションへのアクセスを制御します。PDF などの弱く型付けされたファイルや MediaStore.Downloads クラスにアクセスする場合、アプリは ACTION_OPEN_DOCUMENT
インテントなどのインテントを使用する必要があります。
Android 10 の動作を有効にするには、requestLegacyExternalStorage
マニフェスト属性を使用し、アプリの権限に関するおすすめの設定に沿って設定します。
- Android 9(以前)を対象とするアプリの場合、マニフェスト フラグのデフォルト値は
true
です。 - Android 10 を対象とするアプリのデフォルト値は false です。Android 10 を対象とするアプリで、フィルタ表示されたストレージ ビューを一時的に無効にするには、マニフェスト フラグの値を
true
に設定します。 - インストーラは制限付きの権限を使用して、サンドボックス化されていないストレージに対して許可されているアプリを許可リストに登録します。許可リストに登録されていないアプリはサンドボックス化されません。