基于权限的导出组件访问控制

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"/>

应用基于签名的权限

在您控制或拥有的两个应用之间共享数据时,请使用基于签名的权限。这些权限不需要用户确认,而是检查访问数据的应用是否使用相同的签名密钥进行签名。这种设置提供了更简化的、更安全的用户体验。如果您声明自定义权限,请考虑相应的安全指南

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" />

单任务端点

按照关注点分离设计原则实施您的应用。每个端点应该只执行一组特定的任务,并具有特定的权限。这种良好的设计实践还允许开发人员为每个端点应用细粒度的权限。例如,避免创建一个既服务于日历又服务于联系人的单一端点。

资源