アプリ サンドボックス

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 クラスを使用して保存する必要があります。詳細については、DAC についてのプレビュー ガイドをご覧ください。

Storage のランタイム権限は、MediaStore を介して、強く型付けされたコレクションへのアクセスを制御します。 PDF などの弱く型付けされたファイルや MediaStore.Downloads クラスにアクセスする場合、アプリは ACTION_OPEN_DOCUMENT インテントなどのインテントを使用する必要があります。

Android 10 の動作を有効にするには、requestLegacyExternalStorage マニフェスト属性を使用し、アプリの権限に関するおすすめの設定に沿って設定します。

  • Android 9(以前)を対象とするアプリの場合、マニフェスト フラグのデフォルト値は true です。
  • Android 10 を対象とするアプリのデフォルト値は false です。Android 10 を対象とするアプリで、フィルタ表示されたストレージ ビューを一時的に無効にするには、マニフェスト フラグの値を true に設定します。
  • インストーラは制限付き権限を使用して、サンドボックス化されていないストレージに対して許可されているアプリをホワイトリストに登録します。ホワイトリストに登録されていないアプリはサンドボックス化されます。