OWASP 类别: MASVS-CODE:代码质量
概述
当自定义权限定义缺失或拼写错误,或者清单中相应的android:protectionLevel
属性使用不当时,就会出现与自定义权限相关的风险。
例如,这些风险可以通过创建具有相同名称的自定义权限来利用,但该权限由恶意应用定义,并应用了不同的保护级别。
自定义权限旨在支持与其他应用共享资源和功能。自定义权限的合法用途示例如下:
- 控制两个或多个应用之间的进程间通信 (IPC)
- 访问第三方服务
- 限制对应用共享数据的访问
影响
利用此漏洞的影响是,恶意应用可以访问最初旨在保护的资源。漏洞的影响取决于受保护的资源以及原始应用程序服务关联的权限。
风险:自定义权限错字
自定义权限可能已在清单中声明,但由于错字,使用了不同的自定义权限来保护导出的 Android 组件。恶意应用程序可以利用权限拼写错误的应用程序,方法是:
- 首先注册该权限
- 预测后续应用程序中的拼写
这可以允许应用程序未经授权访问资源或控制受害者应用程序。
例如,易受攻击的应用想要使用权限READ_CONTACTS
保护组件,但意外地将权限拼写为READ_CONACTS
。恶意应用可以声明READ_CONACTS
,因为它不属于任何应用程序(或系统)所有,并可以访问受保护的组件。此漏洞的另一个常见变体是android:permission=True
。true
和false
等值(无论大小写如何)都是权限声明的无效输入,其处理方式与其他自定义权限声明错字类似。要解决此问题,应将android:permission
属性的值更改为有效的权限字符串。例如,如果应用需要访问用户的联系人,则android:permission
属性的值应为android.permission.READ_CONTACTS
。
缓解措施
Android Lint 检查
声明自定义权限时,请使用 Android lint 检查来帮助您查找代码中的错字和其他潜在错误。
命名约定
使用一致的命名约定,以便更容易发现拼写错误。仔细检查应用清单中自定义权限声明的拼写错误。
风险:孤立权限
权限用于保护应用的资源。应用可以在两个不同的位置声明访问资源所需的权限
- AndroidManifest.xml:预定义在 AndroidManifest.xml 文件中(如果未指定,则使用`
<application>
`权限),例如,提供程序权限、接收器权限、活动权限、服务权限; - 代码:在运行时代码中注册,例如,
registerReceiver()
。
但是,有时这些权限并没有在设备上 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
`无需使用与应用`A
`相同的证书签名,即可访问`X
`应用中受该自定义权限保护的所有组件。
如果`B
`在`A
`之前安装,也会发生同样的情况。
缓解措施
如果您只想让与提供应用签名相同的应用可以使用某个组件,则您可以避免定义自定义权限来限制对该组件的访问。在这种情况下,您可以使用签名检查。当您的一个应用请求另一个应用时,第二个应用可以在响应请求之前验证这两个应用是否使用相同的证书签名。
资源
- 最小化您的权限请求
- 权限概述
- 保护级别说明
- CustomPermissionTypo Android Lint
- 如何使用 Android Lint
- 一篇深入解释 Android 权限和有趣的模糊测试结果的研究论文