假设我已经上传了一个应用到 Play 商店,现在我希望我的服务器只接受来自这个应用的连接。
我该怎么做?
为了在您的应用程序和 API 服务器之间实现最佳安全级别,您应该使用 Mobile App Attestation 服务以及 SafetyNet 解决方案,加上 OAUTH2 服务和最后的证书固定来保护 API 服务器和移动应用程序之间的通信通道,如本系列文章中介绍了有关移动 API 技术的内容。
移动应用程序证明服务的作用是通过使用集成在您的应用程序中的 SDK 和在云中运行的服务来保证您的应用程序在运行时没有被篡改或没有在有根设备中运行。
在成功证明应用程序完整性后,将颁发 JWT 令牌并使用只有您的应用程序的 API 服务器和云中的移动应用程序证明服务知道的秘密进行签名。
在 App Attestation 失败的情况下,JWT 会使用 API 服务器不知道的密钥进行签名。
现在,应用程序必须在每个 API 调用中发送请求标头中的 JWT 令牌。这将允许 API 服务器仅在可以验证 JWT 令牌中的签名时服务请求,并在验证失败时拒绝它们。
一旦应用程序不知道移动应用程序证明服务使用的秘密,即使应用程序被篡改、在根设备中运行或通过作为目标的连接进行通信,也无法在运行时对其进行逆向工程一个人在中间攻击。这就是此类服务与 SafetyNet 解决方案相关的亮点所在。
作为旁注,如果您的应用程序直接与第三方服务对话,那么我建议您将该责任委托给 API 服务器,这将防止您的第三方服务在未经授权的情况下代表您使用,因为它现在只提供来自通过完整性挑战的移动应用程序。
那么为什么不只使用 SafetyNet 呢?尽管它是添加到 Android 中的一项很好的安全功能,但它并非旨在用作您的应用程序的唯一安全防御,按照Google 自己的话:
此 API 的目标是让您对运行您的应用程序的设备的完整性充满信心。然后,您可以使用标准 Android API 获取其他信号。您应该将 SafetyNet Attestation API 作为反滥用系统的一部分作为额外的深度防御信号,而不是作为您应用程序的唯一反滥用信号。
在我走之前,我想提请注意 SafetyNet 解决方案中的以下内容:
它是 Google 移动服务 (GMS) 的一部分,因此只能在具有此功能的设备上运行。在某些市场,例如远东地区,有大量设备没有此功能。
可以使用标准的免费 API 密钥进行数量有限的证明调用,因此需要(大概)付费级别的大规模使用。
它主要用于检查特定 Android 设备正在运行的操作系统映像是否被认为是安全和兼容的。因此,它可以被认为是非常先进的根检查,能够检查指示根设备的文件系统更改。
由于 SafetyNet 正在对操作系统映像的哈希进行全面分析,因此它实际上可能非常慢(有时需要几秒钟)。这意味着它不能连续运行,并且在使用它时需要小心以向用户隐藏这种延迟,但又不会为攻击者提供可利用的机会。
SafetyNet 没有专门分析正在运行的应用程序的内存映射来检测检测框架(它依赖于它们只能在有根设备上运行的事实),例如 XPosed 和 Frida。
SafetyNet 确实通过 apkDigestSha256 功能提供了正在运行的应用程序的证明。但是,只有在报告了完整的完整性时才能依赖它。这意味着如果应用程序在任何类型的不寻常或有根设备上运行,则该应用程序的完整性是未知的。一些用户仅出于自定义目的而根植他们的设备,如果移动应用程序占很大比例,那么 SafetyNet 会将他们排除在使用该应用程序之外。在这种情况下,我们想具体了解正在运行的应用程序的完整性,而不是整个系统。SafetyNet 无法做到这一点,但移动应用程序证明服务可以。
为了以一种无法被欺骗的方式执行证明检查,应用程序不能进行自己的检查(因为很明显,这段代码可能会被自己篡改)。因此,需要实现服务器端以可靠地使用该功能。