安卓Binder安全

16

Binder在Android中提供的进程间通信是否受到中间人攻击的保护?是否有提供相关信息的文档?

2个回答

20
Binder采用基于能力的安全模型。每个Binder对象代表一个能力;将该对象交给另一个进程授予该进程访问该能力的权限。从这个角度来看,防止中间人攻击的方法是不将重要的Binder对象交给中间人。如果一个进程没有得到一个Binder对象,它就无法以任何方式访问它。
关于论文中讨论的“跨Binder引用伪造”问题,如果我理解他们所说的特定场景,我认为他们关于用户空间的补充比我同意的要弱一些。我认为他们犯了一个错误,即看待ServiceManager的特殊C代码。严格来说,我认为C++用户空间代码(尤其是Parcel)是Binder架构的一部分。这段代码特别确保在调用其readBinder()和相关方法时处理这些欺骗尝试。
我不同意内核未完全确保数据完整性的说法。我想象唯一的方法是定义标准的类型化数据结构来进行Binder事务,以便可以读取和验证包裹的内容。在我看来,这在内核中需要过多的知识,并且没有实际的好处。不管你在那里放置多少东西,用户空间都需要对传入的事务进行某种验证,以确保它与其期望相匹配。今天,这是在Parcel上进行原始数据读取操作(readBinder()、readString16()、readInt()等)的验证水平来完成的,以避免攻击。将更多的验证推到内核中仍然需要在用户空间验证数据类型是否正确,现在你实际上已经将一些机会从用户空间移动到内核中(由于代码中的错误)。
关于Binder安全性的最后一个问题是,重要的是要意识到,在平台级别上,另有一种基于权限/uid的系统实现了Binder基础设施之上的另一个重要安全模型。服务可以检查传入调用的UID,以验证它们是否与其允许的权限相匹配。这个安全模型还存在另一个欺骗漏洞。一个典型的情况是,一个应用程序接收到了 ActivityManager Service 的 IBinder(因为每个人都可以获得)。ActivityManager Service 的 API 严重依赖于检查传入调用的 uid,以确定允许什么 - 例如,如果调用 bindService(),它将检查该 uid 是否有权限绑定到给定的服务。恶意应用程序可能通过将 Activity Manager IBinder 交给另一个系统服务来尝试在这里玩游戏,例如作为 IWindow 提供给 window manager。如果它知道第二个系统服务将进行的事务,则可以设置事务,使其执行一个它认为是 resizeWindow() 的调用,但实际上当它放入 ActivityManager 时变成了 bindService() 的调用(如果这两个调用映射到相同的事务 ID)。
这种漏洞存在是因为 Binder 系统没有任何类型,“方法”调用只是使用整数事务代码和数据缓冲区发送的事务。
为了防止这种情况发生,aidl 生成的用户空间类型化接口总是在其事务缓冲区的开头放置要调用的接口名称,并且事务接收代码会检查缓冲区前面的接口名称以确保其与自己的接口匹配。这样,在上述情况下的欺骗者将被捕获,当 ActivityManager 看到它有一个接收窗口接口的传入调用时。
无论如何,对于大多数 Android 开发人员而言,基于 uid 的安全性与核心 binder 能力模型一样重要。在某些情况下,您将通过限制哪些进程可以访问 Binder 来实施安全性。例如,每个活动都有一个 IBinder 表示,只有系统进程和运行该活动的进程共享。
在其他情况下,IBinder 对象将与任何感兴趣的进程共享,但在调用点基于 uid 强制执行安全性。如果您正在使用 aidl 为此类接口提供标准实现,则可以根据想要应用于 uid 的含义来自己实现此类安全性。例如,您可以使用标准设施将权限与 uid 关联起来,并询问包管理器以确定传入的 uid 是否具有权限。

感谢 @hackbod 提供的非常有用的关于 Android Binder 机制的深入文档。这份文档应该附加在 Binder 的 JavaDoc 或其他地方,因为它要比目前提供的文档更为全面 :-) - Tom
这是一个非常深入的解释,但我不理解这段话:aidl生成的用户空间类型接口总是在它们的事务缓冲区的开头放置它们打算调用的接口名称,而事务的接收代码会检查缓冲区前面的接口名称以确保它与自己的接口匹配。我找不到生成文件中的那个缓冲区。你能再详细解释一下吗? 非常感谢。 - Max
2
在AIDL生成的Java文件的代理(发送方)部分中,您将看到每个方法开头的_data.writeInterfaceToken(DESCRIPTOR)DESCRIPTOR是接口名称,_data是由mRemote.transact使用的事务缓冲区。在同一文件的存根(接收方)侧,您将看到在每个事务案例的开头调用enforceInterface(DESCRIPTOR)。这就是上面提到的检查所在的地方。 _datadata是类android.os.Parcel的对象,而mRemote是类android.os.IBinder的对象。 - Paul Ratazzi

2
Binder存在一个已知的安全漏洞,可能会使其容易受到中间人攻击:http://crypto.hyperlink.cz/files/xbinder.pdf。引用TFA的话来说:“攻击者可以管理目标进一步传递或调用其‘受保护’的绑定器(攻击者未被邀请直接调用)。我们称之为跨绑定器引用伪造(XBRF)”。作者接着说,在Android中有防御此类攻击的措施,但在某些情况下,攻击进程准备的事务数据经过仔细操作仍可能导致成功的XBRF利用。人们得出的印象是,对于精心编写的代码,Binder似乎相对安全,但存在一定风险。

这是对原问题的一个很好的回答。然而,它并没有回答如何验证绑定器通信的两个端点。 - Vincent Cantin
根据TFA,在Android代码中有一些缓解措施,但它们不一定足够。因此,开发人员剩下的措施是在通信进程之间使用数字签名。 - Yusuf X

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接