安卓应用安全指南 5.2.2 权限和保护级别 规则书
5.2.2 权限和保护级别 规则书
原书:Android Application Secure Design/Secure Coding Guidebook
译者:飞龙
使用内部权限时,请确保遵循以下规则:
5.2.2.1 Android 的系统危险权限只能用于保护用户资产(必需)
由于不建议你使用自己的危险权限(请参阅“5.2.2.2 你自己的危险权限不得使用(必需)”),我们将在使用 Android 操作系统的系统危险权限的前提下进行。
不像其他三种类型的权限,危险权限具有这个特性,需要用户同意授予应用权限,在声明了危险权限的设备上安装应用时,将显示以下屏幕:随后, 用户可以知道应用试图使用的权限级别(危险权限和正常权限),当用户点击“安装”时,应用将被授予权限,然后安装。
应用可以处理开发人员希望保护的用户资产。 我们必须意识到,危险的权限只能保护用户资产,因为用户只是授予权限的人。 另一方面,开发人员想要保护的资产不能用上述方法保护。
例如,假设应用具有一个组件,只与内部应用通信,它不允许从其他公司的任何应用访问该组件,并且通过危险权限的保护来实现。 当用户根据判断,向另一家公司的应用授予权限时,需要保护的内部资产可能通过应用授权来利用。 为了在此类情况下保护内部资产,我们建议使用内部定义的签名权限。
5.2.2.2 不能使用你自己的危险权限(必需)
即使使用内部定义的危险权限,在某些情况下,屏幕提示“请求允许来自用户的权限”也不会显示。 这意味着,有时根据用户判断来请求权限的特性(危险权限的特征)不起作用。 因此,指导手册规定“不得使用内部定义的危险权限”。
为了解释它,我们假设有两种类型的应用。 第一种类型的应用定义了内部危险权限,并且它让受此权限保护的组件公开。 我们称之为ProtectedApp
。 另一个是我们称为AttackerApp
,它试图利用ProtectedApp
的组件。 我们还假设AttackerApp
不仅声明了使用它的权限,而且还定义了相同的权限。
在以下情况下,AttackerApp
可以在未经用户同意的情况下,使用ProtectedApp
的组件:
- 当用户安装
AttackerApp
时,安装将在没有屏幕提示的情况下完成,它要求用户授予应用危险权限。 - 同样,当用户安装
ProtectedApp
时,安装将会完成而没有任何特别的警告。 - 当用户启动
AttackerApp
后,AttackerApp
可以访问ProtectedApp
的组件,而不会被用户检测到,这可能会导致损失。
这种情况的原因在下面解释。 当用户尝试首先安装AttackerApp
时,在特定设备上,尚未使用uses-permission
来定义声明的权限。 没有发现错误,Android 操作系统将继续安装。 由于只有在安装时用户才需要同意危险权限,因此已安装的应用将被视为已被授予权限。 因此,如果稍后安装的应用的组件受到名称相同的危险权限的保护,则在未经用户同意的情况下,事先安装的应用将能够利用该组件。
此外,由于在安装应用时,确保存在 Android OS 定义的系统危险权限,每次安装具有uses-permission
的应用时,都会显示用户验证提示。 只有在自定义危险权限的情况下才会出现此问题。 在写这篇文章的时候,还没有开发出可行方法,在这种情况下保护组件的访问。 因此,你不得使用你自己的危险权限。
5.2.2.3 你自己的签名权限必需仅在提供方定义(必需)
如“5.2.1.2 如何使用内部定义的签名权限,在内部应用之间进行通信”中所示,在进行内部应用之间的内部通信时,通过检查签名权限,可以确保安全性。 当使用这种机制时,保护级别为签名的权限的定义,必须写在具有组件的提供方应用的AndroidManifest.xml
中,但用户方应用不能定义签名权限。
此规则也适用于signatureOrSystem
权限。原因如下。
我们假设,在提供方应用之前安装了多个用户方应用,并且每个用户方应用,不仅要求提供方应用定义的签名权限,而且还定义了相同的权限。 在这些情况下,所有用户方应用都可以在安装提供方应用之后,立即访问提供方应用。 随后,卸载先安装的用户方应用时,权限的定义也将被删除,然后该权限将变为未定义。 因此,其余的用户方应用将无法访问提供方应用。
以这种方式,当用户方应用定义了一个自定义权限时,它可能会意外地将权限设置为未定义。因此,只有提供需要保护的组件的提供方应用才应该定义权限,并且必须避免在用户方定义权限。
通过如上所述的那样,自定义权限将在安装提供方应用时由 Android OS 应用,并且在卸载应用时权限将变得未定义。因此,由于权限定义总是对应提供方应用的定义,因此可以提供适当的组件并对其进行保护。请注意,这个观点成立,是因为对于内部定义的签名权限,用户方应用被授予权限,而不管应用在相互通信中的安装顺序 [24]。
[24] 如果使用正常/危险权限,并且用户方应用安装在提供方应用之前,则该权限将不会授予用户方应用,权限仍未定义。 因此,即使在安装了提供方应用之后,也不能访问组件。
5.2.2.4 验证内部定义的签名权限是否由内部应用定义(必需)
实际上,只有通过AnroidManifest.xml
声明签名权限并使用权限来保护组件,才能说是足够安全。 此问题的详细信息,请参阅“高级主题”部分中的“5.2.3.1 绕过自定义签名权限的 Android 操作系统特性及其对策”。
以下是安全并正确使用内部定义的签名权限的步骤。
首先,在AndroidManifest.xml
中编写如下代码:
在提供方应用的AndroidManifest.xml
中定义内部签名权限。(权限定义)
例如:<permission android:name="xxx" android:protectionLevel="signature" />
在提供方应用的AndroidManifest.xml
中,使用要保护的组件的权限属性强制执行权限。 (执行权限)
例如:<activity android:permission="xxx" ... >...</activity>
在每个用户方应用的AndroidManifest.xml
中,使用uses-permission
标签声明内部定义的签名权限,来访问要保护的组件。 (使用权限声明)
例如:<uses-permission android:name="xxx" />
下面,在源代码中实现这些:
在处理组件的请求之前,首先验证内部定义的签名权限是否由内部应用定义。 如果不是,请忽略该请求。 (保护提供方组件)
在访问组件之前,请先验证内部定义的签名权限是否由内部应用定义。 否则,请勿访问组件(用户方组件中的保护)。
最后,使用 Android Studio 的签名功能之前,执行下列事情:
使用相同的开发人员密钥,对所有互相通信的应用的 APK 进行签名。
在此,对于如何实现“确认内部定义签名权限已由内部应用定义”的具体要点,请参阅“5.2.1.2 如何使用内部定义的签名权限,在内部应用之间进行通信”。
此规则也适用于signatureOrSystem
权限。
5.2.2.5 不应该使用你自己的普通权限(推荐)
应用只需在AndroidManifest.xml
中使用uses-permission
声明,即可使用正常权限。 因此,你不能使用正常权限,来保护组件免受恶意软件的安装。
此外,在使用自定义普通权限进行应用间通信的情况下,应用是否可以被授予权限取决于安装顺序。 例如,当你安装已声明使用普通权限的应用(用户方法),并且在另一应用(提供者端)之前,它拥有已定义权限的组件,用户方应用将无法 访问受权限保护的组件,即使稍后安装提供方应用也是如此。
作为一种方法,防止由于安装顺序而导致的应用间通信丢失,你可以考虑在通信中的每个应用中定义权限。 通过这种方式,即使在提供方应用之前安装了用户方应用,所有用户方应用也将能够访问提供方应用。 但是,它会产生一种情况,即在卸载第一个安装的用户方应用时,权限未定义。 因此,即使有其他用户方应用,他们也无法访问提供方应用。
如上所述,存在损害应用可用性的风险,因此不应使用你自己的正常权限。
5.2.2.6 你自己的权限名称的字符串应该是应用包名的扩展(推荐)
当多个应用使用相同名称定义权限时,将使用先安装的应用所定义的保护级别。 如果首先安装的应用定义了正常权限,并且稍后安装的应用使用相同的名称定义了签名权限,则签名权限的保护将不可用。 即使没有恶意的意图,多个应用之间的权限名称冲突,也可能导致任何应用的行为成为意外的保护级别。 为防止发生此类事故,建议权限名称扩展于定义权限的应用的包名(以它开头),如下所示。
(package name).permission.(identifying string)
例如,为org.jssec.android.sample
包定义READ
访问权限时,以下名称将是首选。
org.jssec.android.sample.permission.READ