エクスポートされたコンポーネントに対する権限ベースのアクセス制御

OWASP カテゴリ: MASVS-PLATFORM: プラットフォームのインタラクション

概要

Android 権限は、制限付きのデータまたはアクションへのアクセスをリクエストするためにアプリのマニフェストで宣言される文字列識別子であり、Android フレームワークによって実行時に適用されます。

Android の権限レベルは、権限に関連する潜在的なリスクを示します。

  • 標準: 低リスクの権限。インストール時に自動的に付与されます。
  • 危険: 機密性の高いユーザーデータへのアクセスを許可する可能性のある、リスクの高い権限。実行時にユーザーの明示的な承認が必要
  • 署名: 権限を宣言したアプリと同じ証明書で署名されたアプリにのみ付与されます。通常は、システムアプリや同じデベロッパーのアプリ間のやり取りに使用されます。

権限ベースのアクセス制御に関連する脆弱性は、アプリのコンポーネント(アクティビティレシーバコンテンツ プロバイダサービスなど)が次のすべての条件を満たしている場合に発生します。

  • コンポーネントが Manifest 内の android:permission に関連付けられていない。
  • コンポーネントが、ユーザーがすでに承認している権限が存在する機密性の高いタスクを実行する。
  • コンポーネントがエクスポートされている。
  • コンポーネントは、手動(マニフェストまたはコードレベル)の権限チェックを行いません。

この場合、悪意のあるアプリは、脆弱なコンポーネントの権限を悪用し、脆弱なアプリの権限を悪意のあるアプリにプロキシすることで、機密性の高いアクションを実行できます。

影響

脆弱なコンポーネントをエクスポートすると、機密リソースへのアクセスや機密性の高いアクションの実行に使用される可能性があります。この望ましくない動作の影響は、脆弱なコンポーネントのコンテキストとその権限によって異なります。

リスクの軽減

機密性の高いタスクに権限を必須にする

機密情報に関わる権限を持つコンポーネントをエクスポートする場合は、受信リクエストに対しても同じ権限が必要になります。Android Studio IDE には、レシーバサービスの lint チェックがあり、この脆弱性を見つけて適切な権限を要求することを推奨します。

デベロッパーは、受信リクエストに対する権限を、Manifest ファイル内で宣言するか、サービスの実装時にコードレベルで要求できます。次に例を示します。

XML

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

    <application ...>
        <service android:name=".MyExportService"
                 android:exported="true"
                 android:permission="android.permission.READ_CONTACTS" />

        </application>
</manifest>

Kotlin

class MyExportService : Service() {

    private val binder = MyExportBinder()

    override fun onBind(intent: Intent): IBinder? {
        // Enforce calling app has the required permission
        enforceCallingPermission(Manifest.permission.READ_CONTACTS, "Calling app doesn't have READ_CONTACTS permission.")
        // Permission is enforced, proceed with export logic
        return binder
    }

    // Inner class for your Binder implementation
    private inner class MyExportBinder : Binder() {
        // Permission is enforced, proceed with export logic
    }
}

Java

public class MyExportService extends Service {

    @Override
    public IBinder onBind(Intent intent) {
        // Enforce calling app has the required permission
        enforceCallingPermission(Manifest.permission.READ_CONTACTS, "Calling app doesn't have READ_CONTACTS permission.");

        return binder;

    }

    // Inner class for your Binder implementation
    private class MyExportBinder extends Binder {
        // Permission is enforced, proceed with export logic

    }
}

コンポーネントをエクスポートしない

どうしても必要な場合を除き、機密性の高いリソースにアクセスできるコンポーネントはエクスポートしないでください。これを行うには、Manifest ファイルの android:exported をコンポーネントの false に設定します。API レベル 31 以降では、この属性はデフォルトで false に設定されています。

XML

<activity
    android:name=".MyActivity"
    android:exported="false"/>

署名ベースのパーミッションを適用する

自身が管理または所有する 2 つのアプリ間でデータを共有する場合は、署名ベースの権限を使用します。署名ベースの権限ではユーザーの確認が不要です。代わりに、データにアクセスするアプリが同じ署名鍵で署名されているかどうかがチェックされます。この設定により、より効率的でセキュアなユーザー エクスペリエンスを実現できます。カスタム権限を宣言する場合は、対応するセキュリティ ガイドラインを検討してください。

XML

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapp">
    <permission android:name="my_custom_permission_name"
                android:protectionLevel="signature" />

単一タスク エンドポイント

関心分離設計原則に沿ってアプリを実装します。各エンドポイントは、特定の権限を持つ特定のタスクのみを実行する必要があります。この優れた設計手法により、デベロッパーはエンドポイントごとにきめ細かい権限を適用することもできます。たとえば、カレンダーと連絡先の両方を提供する単一のエンドポイントを作成しないでください。

リソース