自定义权限

OWASP 类别: MASVS-CODE:代码质量

概述

当自定义权限定义丢失或拼写错误,或者当 android:protectionLevel 属性在清单中使用不当时,就会出现与自定义权限相关的风险。

例如,这些风险可以通过创建具有相同名称的自定义权限来利用,但该权限由恶意应用定义,并应用了不同的保护级别。

自定义权限旨在允许与其他应用共享资源和功能。自定义权限的合法使用示例如下

  • 控制两个或多个应用之间的进程间通信 (IPC)
  • 访问第三方服务
  • 限制对应用共享数据的访问

影响

利用此漏洞的影响是,恶意应用可以访问最初旨在保护的资源。漏洞的影响取决于受保护的资源和原始应用服务关联的权限。

风险:自定义权限拼写错误

自定义权限可能会在清单中声明,但由于拼写错误,会使用不同的自定义权限来保护导出的 Android 组件。恶意应用可以通过以下方式利用拼写错误的权限的应用:

  • 首先注册该权限
  • 预期后续应用中的拼写

这可能允许应用未经授权访问资源或控制受害应用。

例如,易受攻击的应用想要使用权限 READ_CONTACTS 来保护组件,但意外地将权限拼写错误为 READ_CONACTS。恶意应用可以声明 READ_CONACTS,因为它不属于任何应用(或系统)所有,并获得对受保护组件的访问权限。此漏洞的另一个常见变体是 android:permission=True。无论大小写如何,诸如 truefalse 之类的值都是权限声明的无效输入,并且与其他自定义权限声明拼写错误的处理方式类似。要解决此问题,应将 android:permission 属性的值更改为有效的权限字符串。例如,如果应用需要访问用户的联系人,则 android:permission 属性的值应为 android.permission.READ_CONTACTS

缓解措施

Android Lint 检查

在声明自定义权限时,使用 Android lint 检查来帮助您查找代码中的拼写错误和其他潜在错误。

命名规范

使用一致的命名规范可以使拼写错误更容易被发现。仔细检查应用清单中自定义权限声明的拼写错误。


风险:孤立权限

权限用于保护应用的资源。应用可以在两个不同的位置声明访问资源所需的权限

但是,有时这些权限未在设备上 APK 清单中由相应的`<permission>` 标签定义。在这种情况下,它们被称为**孤立权限**。这种情况可能由多种原因导致,例如

  • 清单和包含权限检查的代码之间的更新可能存在不同步
  • 包含权限的 APK 可能未包含在构建中,或者包含了错误的版本
  • 检查或清单中的权限名称可能拼写错误

恶意应用可能会定义一个孤立权限并获取它。如果发生这种情况,则信任孤立权限来保护组件的特权应用可能会受到损害。

在特权应用使用权限来保护或限制任何组件的情况下,这可能会授予恶意应用对该组件的访问权限。例如,启动受权限保护的活动、访问内容提供程序或广播到受孤立权限保护的广播接收器。

它还可能导致特权应用被欺骗,使其相信恶意应用是合法应用,从而加载文件或内容。

缓解措施

确保应用用于保护组件的所有自定义权限也在清单中定义。

应用使用自定义权限`my.app.provider.READ` 和`my.app.provider.WRITE` 来保护对内容提供程序的访问

XML

<provider android:name="my.app.database.CommonContentProvider" android:readPermission="my.app.provider.READ" android:writePermission="my.app.provider.WRITE" android:exported="true" android:process=":myappservice" android:authorities="my.app.database.contentprovider"/>

应用还定义并使用这些自定义权限,从而阻止其他恶意应用这样做

XML

<permission android:name="my.app.provider.READ"/>
<permission android:name="my.app.provider.WRITE"/>
<uses-permission android:name="my.app.provider.READ" />
<uses-permission android:name="my.app.provider.WRITE" />

风险:错误使用 android:protectionLevel

此属性描述权限的潜在风险级别,并指示系统在决定是否授予权限时应遵循的程序。

缓解措施

避免使用“normal”或“dangerous”保护级别

在权限上使用**normal** 或**dangerous**`protectionLevel` 意味着大多数应用都可以请求并获得权限

  • “normal”只需要声明它
  • “dangerous”会被许多用户批准

因此,这些`protectionLevels` 提供的安全性很低。

使用签名权限(Android >= 10)

尽可能使用签名保护级别。使用此功能可确保只有与创建权限的应用具有相同证书签名的其他应用才能访问这些受保护的功能。确保使用专用(未重复使用)的签名证书,并将其安全地存储在密钥库中。

在清单中按如下方式定义自定义权限

XML

<permission
    android:name="my.custom.permission.MY_PERMISSION"
    android:protectionLevel="signature"/>

将访问权限(例如,活动)限制为仅授予此自定义权限的应用,如下所示

XML

<activity android:name=".MyActivity" android:permission="my.custom.permission.MY_PERMISSION"/>

任何其他与声明此自定义权限的应用具有相同证书签名的应用都将被授予对`.MyActivity` 活动的访问权限,并且需要在其清单中声明如下

XML

<uses-permission android:name="my.custom.permission.MY_PERMISSION" />

注意签名自定义权限(Android < 10)

如果应用的目标是 Android < 10,则每当应用的自定义权限因卸载或更新而被删除时,恶意应用可能仍然能够使用这些自定义权限,从而绕过检查。这是由于权限提升漏洞(CVE-2019-2200)导致的,该漏洞已在 Android 10 中修复

这是(连同竞争条件风险)建议使用签名检查而不是自定义权限的原因之一。


风险:竞争条件

如果合法应用`A` 定义了其他`X` 应用使用的签名自定义权限,但随后被卸载,则恶意应用`B` 可以使用不同的`protectionLevel`(例如,normal)定义相同的自定义权限。这样,`B` 就可以访问`X` 应用中受该自定义权限保护的所有组件,而无需使用与应用`A` 相同的证书签名。

如果`B` 在`A` 之前安装,也会发生这种情况。

缓解措施

如果只想使组件可供与提供应用具有相同签名的应用使用,则可能能够避免定义自定义权限来限制对该组件的访问。在这种情况下,可以使用签名检查。当其中一个应用请求另一个应用时,第二个应用可以在遵守请求之前验证这两个应用是否都使用相同的证书签名。


资源