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

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

概要

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

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

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

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

  • コンポーネントが Manifestandroid: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" />

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

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

リソース