
我们讨论了安全问题和解决方案,例如数据存储,网络通信,密码和身份验证策略。在本期中,我们将从组件之间的通信,数据验证和安全保护等方面继续实践Android软件安全开发。
组件之间的通信
组件之间通信的安全性问题是Android独有的,也是软件中最常见的问题。
让我们首先回顾一下组件之间的通信机制。 Android具有四种类型的组件:活动,服务,广播和内容提供程序。在同一软件中或在不同软件之间,前三个组件使用Intent相互调用,并使用ContentResolver对象访问内容提供者以共同实现软件功能。使用Intent,您可以显式或隐式调用它:
如以下代码所示:

无论是显式的还是隐式的,如果要在应用程序中调用它,则需要调用的组件都暴露在外面。默认情况下,服务,广播和内容提供者是公开的,确认Intent过滤器的活动性也是公开的。
抽象地讲,组件A需要调用组件B才能期望B完成某个功能。它可以将一些数据发送到组件B,并且还可以在执行B之后获得返回结果。在此模型中,问题在A和B之间出现,不一定是可信赖的。
如果B被暴露,则任何软件都可以调用它,包括攻击者编写的软件。攻击者可能但并非总是成功:

如果A使用隐式调用,则任何软件都可以实施其操作以响应该调用。攻击者可能(但不一定总是成功):
这可能更抽象。下面我们分别讨论这两种情况。
组件暴露的问题
看一个例子。在第三方深度定制的ROM中,预装了名为Cit.apk的软件,用于手机的硬件测试。其AndroidManifest.xml部分如下:

如您所见,它声明一个名为.CitBroadcastReceiver的,响应名为android.provider.Telephony.SECRET_CODE的操作,并指定URI格式。
让我们再次查看该的代码片段(以下代码是通过反编译获得的,并且可能与软件源代码不完全相同)

可以看出,当调用此并且所提供的URI中的host字段为284时,将使用root特权调用本地bugreport工具,结果将输出到m_logFileName指定的文件中。

默认情况下,该是公开的,因此该可以被其他软件调用,代码如下:

执行这四行代码后,将触发CitBroadcast-Receiver代码。从上下文来看,输出文件m_logFileName位于SD卡上,任何软件都可以随意读写。因此,攻击者可以获得错误报告的输出,其中包含大量的系统数据和用户数据。
请注意,在此示例中,攻击者的软件不需要任何特殊权限,尤其是root用户权限。这种由于组件暴露而获得额外权限的攻击称为权限重新授权。
如何避免由组件暴露引起的安全问题?必须公开一些组件,例如入口活动,或者确实提供外部服务或跨软件协作;但是某些组件不需要暴露。接下来,我们分别讨论。
不需要暴露的组件
回想一下,默认情况下,服务,广播和内容提供程序是公开的,并且据说Intent过滤器的活动性也是公开的。如果仅在同一软件中通过代码调用它们,则应将它们设置为不公开。在AndroidManifest.xml的此组件中添加属性android:exported =“ false”很容易。
需要暴露的组件
如果该组件需要暴露于外界,则应通过自定义权限对其进行限制。

首先,在实现被调用组件的软件的Android-Manifest.xml中自定义权限:

接下来,为被调用的组件添加此权限限制,即在AndroidManifest.xml中将该android:permission属性添加到此组件:

另一种方法是在组件的实现代码中使用Context.checkCallingPermission()来检查调用方是否具有此权限。
最后,要调用此公开组件,调用者所在的软件应声明使用此许可权,即在AndroidManifest.xml中添加相应的use-permission声明。
此外,此组件提出的要求也可以分为两种情况。
此外,对于内容提供者,可以为读取数据和以更精细的方式写入数据设置不同的权限。相应的清单标签是android:readPermission和android:writePermission。
隐式调用的问题

隐式调用的主要问题是被劫持,或者读取了Intent携带的数据。
为了劫持该呼叫,攻击者可以实施一个恶意组件,该组件声明相同的Intent过滤器。在多个组件可以响应同一Intent的情况下,如果调用了活动,则系统将弹出一个界面,要求用户选择多个软件。攻击者可以模仿真实软件的图标和名称来吸引用户点击;如果称为服务,系统将随机选择一个服务。如果调用了接收方,则系统将一一向这些接收方发送Intent。
劫持呼叫之后,攻击者可以(但并不总是成功):
限于篇幅,我们不提供这些情况的示例代码。让我们看一下如何解决此类问题。
无需隐式调用
除了基于Intent类中现有ACTION的隐式调用外,大多数隐式调用都属于以下两种情况:来自同一软件中不同组件的调用;同一开发人员在不同软件之间进行调用。
实际上,在两种情况下,都已经可以确定在开发期间要调用哪个组件。因此,可以避免隐式调用,并且可以更改基于组件名称的显式调用。
需要隐式呼叫
除了使用sendBroadcast(Intent)发送广播外,还有另一种方法sendBroadcast(Intent,String),其第二个参数可以指定收件人所需的权限。
据我所知,如果要呼叫活动或服务,没有简单的方法来限制接收者的许可。在Android文档中,建议可以对Binder和AIDL进行自定义,以实现通信双方之间的相互验证,但是实际实现并不容易,因此政府不建议这样做。
数据验证
无论是客户端还是服务器,在处理从外部获取的数据之前,都应对数据的有效性进行判断和验证。这主要是指是否包含格式错误的数据。
在Web开发中,服务器需要验证用户提交的数据的有效性,否则容易受到众所周知的SQL注入之类的攻击。在移动开发中也不例外。尽管客户端和服务器在基础通信协议中对用户是透明且不可见的,但开发人员不应假定双方传输的数据始终与预先设计的数据一致。同样,在从UI元素读取用户的输入并读取本地存储的数据之后,也应在使用前验证有效性。
本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/shouji/article-339395-1.html
雷不丝
杨洋加油