在受限环境中使用移动应用安全 API 访问

Secure API access with mobile apps in restricted environments

在我们当前的项目中,IT 规则禁止任何非 PROD 的内容从 Internet 公开访问。必须严格限制对开发和审查环境的访问。也就是说,该项目还包括与云托管 API 层一起开发的移动应用程序。

笼统地说,使用移动应用保护 DEV/REVIEW 阶段 API 安全的常用方法是什么?我们提出了以下想法:

每一种方法都有多个问题需要解决,但我想在深入了解其中任何一种之前先了解大局。

IP 白名单

IP whitelist on the in the ingress to the API (least secure, but easiest to use)

如果您将非贵公司办公室独有的 IP 列入白名单,我认为这是最不安全的 and/or 该 IP 是贵公司独有的,但被 public WI-fis 使用在贵公司。

此外,如果您需要将远程开发人员和测试人员的访问权限列入白名单,而这些远程开发人员和测试人员可能位于或不位于 public IP 中,此解决方案将存在风险,因为人们总是将便利置于安全之上,他们可能会要求将来自他们喜欢工作的咖啡店、购物中心、女朋友家等的 IP 列入白名单..

所以我会放弃这个选项,除非你在一个小办公室里,你的 public WI-fi(供你的客户使用的那个)与你的主互联网使用不同的 IP连接。

VPN 网关

VPN gateway to the hosting environment, with corresponding DEV / test devices configuration

这种方法似乎是最明智的做法,只有被授权访问 VPN 的人才能使用隐藏在它后面的资源,甚至可以在 public [=61] 中使用 VPN =].

双向 TLS 认证

Mutual TLS authentication (most difficult to implement and operate)

虽然难以实施和操作,但它们也存在可以绕过的证书固定问题。

关于 this article 关于在移动应用程序中固定,我们可以了解实现证书固定是多么容易:

// simplified android example

CertificatePinner certificatePinner = new CertificatePinner.Builder()
       .add("publicobject.com", "sha256/afwiKY3RxoMmLkuRW1l7QsPZTJPwDS2pdDROQjXw8ig=")
       .add("bikewise.org", "sha256/x9SZw6TwIqfmvrLZ/kz1o0Ossjmn728BnBKpUFqGNVM=")
       .build();

OkHttpClient client = OkHttpClient.Builder()
         .certificatePinner(certificatePinner)
         .build();

在同一篇文章中,我们还可以看到固定如何成为一场噩梦...正如您所说,难以操作!!!

The main difficulty with pinning is not technical but operational. By embedding fixed information about the server (the certificate) into the app you create a dependency between the two, as the term pinning implies. This means that whenever you (or your ops team) are planning to change the certificate on the server you must:

  • Generate the certificate in advance
  • Build, test and publish a new version of the app with both the new certificate and the old one.
  • Wait for most (80%, 90%, 99% ?) of your users to upgrade to the new version
  • Change the cert on the server
  • Build, test and publish a new version of the app with the old certificate removed.

好像这还不够,可以使用内省框架绕过证书固定,正如我在上面链接的同一篇文章中指出的那样:

Even if you successfully navigate the operational difficulties inherent in implementing pinning, there is still the giant pink elephant in the room that is unpinning. The development of hooking frameworks such as Xposed has reached such a level of sophistication that a rich ecosystem of modules exists to target various aspects of Android apps including the pinning functionality of HTTP libraries. Using them is very straightforward.

另一种方法 - 加倍努力

That said, the project also includes mobile apps that are developed together with the cloud-hosted API layer.

在移动应用程序的上下文中,您可以使用一种被设计为移动应用程序证明的技术,该技术可以在所有环境中使用,以保护 API 服务器,对于移动应用程序,不响应请求并非源自您为该特定环境发布、签名和注册的正版移动应用程序二进制文件。

移动应用认证

移动应用证明服务的作用是在 run-time 保证您的移动应用未被篡改或未 运行 在已获得 root 权限的设备中。它包含一个集成在后台运行的移动应用程序中的 SDK,不会影响用户体验,并与云中的服务 运行 通信以证明移动应用程序和设备的完整性 运行上。

在成功证明移动应用程序完整性后,将发布一个短期 JWT 令牌并使用只有 API 服务器和云中的移动应用程序证明服务知道的秘密进行签名。如果移动应用证明失败,JWT 令牌将使用 API 服务器不知道的秘密进行签名。

移动应用程序必须在请求的 headers 中发送 JWT 令牌,以进行非常 API 的调用。这允许 API 服务器仅在可以验证 JWT 令牌中的签名和过期时间时才为请求提供服务,并在验证失败时拒绝它们。

任何试图在 run-time 验证移动应用证明颁发的 JWT 令牌是有效还是无效的人都不会成功,因为它们之间的唯一区别是用于签名的秘密,并且这个秘密只有移动应用证明服务和 API 服务器随时知道。这意味着即使是移动应用程序也不拥有秘密,因此不知道是否正在向 API 服务器发送有效或无效的 JWT 令牌。

结论

从你的 3 种解决方案中,我会选择 VPN 方法,如果你想更进一步,你应该考虑实施你自己的移动应用证明服务,以保证移动 APIs 仅适用于任何环境与特定 environment/stage 的移动应用程序通信,并拒绝来自任何其他来源的请求。该解决方案甚至允许您的手机 API 托管在 public 域上,而不会泄露任何数据,因此不需要在其前面安装 VPN。