OWASP 类别: MASVS-PLATFORM:平台互动
概览
Android 权限是应用清单中声明的字符串标识符,用于请求访问受限数据或执行受限操作,由 Android 框架在运行时强制执行。
Android 权限级别表示与权限相关的潜在风险:
- 普通:低风险权限,会在安装时自动授予
 - 危险:可能允许访问敏感用户数据的高风险权限,需要在运行时获得用户明确批准
 - 签名:仅向使用与声明权限的应用相同的证书进行签名的应用授予,通常用于系统应用或同一开发者的应用之间的互动
 
当应用的组件(如 activity、接收器、content provider 或服务)符合以下所有条件时,就会发生与基于权限的访问权限控制相关的漏洞:
- 组件未与 
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" />
单任务端点
遵循关注分离设计原则来实现应用。每个端点都应仅使用特定权限执行一小部分特定任务。这种良好的设计实践还允许开发者为每个端点应用精细的权限。例如,请避免创建一个同时提供日历和通讯录服务的端点。
资源
- “安全保护”博客中的 Android 访问受应用保护的组件
 - Content Provider 最佳实践
 - 运行时(危险)权限
 - 问题分离设计原则
 - Android 权限文档
 - Android 广播接收器安全提示
 - Android 服务安全提示
 - Android 12(API 31)导出的默认值设为“false”
 - Lint 检查:导出的 PreferenceActivity 不应导出
 - lint 检查:导出的接收器不需要权限
 - lint 检查:导出的服务不需要权限