确保 Web 服务仅由授权应用程序访问

信息安全 Web应用程序 移动的 休息
2021-08-25 23:37:45

前言

我的移动应用程序允许用户在我的服务上创建帐户。除了能够使用外部身份验证提供商(如 Facebook)登录之外,我还想为用户提供使用电子邮件地址创建帐户的选项。

通常,对我的 Web 服务的所有调用都通过基于 HTTPS 的基本身份验证进行身份验证。但是,创建帐户功能(也通过 HTTPS)没有任何身份验证 - 因为用户还没有任何凭据。

如果我正在编写一个网站,我会使用 Captcha 来阻止我的数据库通过脚本填充虚假帐户。

问题

如何验证新用户请求来自我的应用程序实例而不是机器人?

如果所有数据都通过 HTTPS 发送,那么应用程序存储的密码是否足以说“嘿,是我!”?做这样的事情的最佳实践是什么?

细化

服务器是使用 Spring Framework 和 Spring Security 用 Ja​​va 编写的。它托管在 App Engine 上。成本是一个问题(网络和计算)。该应用程序是一款手机游戏。我不存储信用卡号码等敏感信息。但是,我确实会跟踪用户在 Apple 和 Android 商店的购买情况。我最关心的是玩家体验。我不希望黑客破坏系统并破坏某人对游戏的享受。我还需要确保玩家在创建帐户时面临尽可能少的障碍。

更新/澄清

我正在寻找一种方法来确保对服务的所有调用都来自我的应用程序实例。用户帐户已经受到保护,因为无状态服务要求他们在每次请求时都发送凭据。没有会话,也没有 cookie。

我需要在不安全的呼叫(例如创建新帐户)上停止垃圾邮件。我不能使用验证码,因为它不适合应用程序的流程。

4个回答

底线是你需要在你的应用程序中嵌入一个秘密。不幸的是,DRM(或多或少是您想要实现的目标)是不可能的。有权访问您的应用程序的人将始终能够恢复嵌入的机密,无论您采取什么措施来保护它。

也就是说,你可以做很多事情来让你的嵌入秘密很难恢复。

  • 在运行时构建它- 不要将秘密存储在应用程序中任何位置的字符串或配置文件中。而是从运行时的一系列计算中得出它。这可以阻止攻击者简单地使用 hexeditor 浏览您的应用程序。

  • 永远不要通过网络发送- 使用具有 >128 位随机数的某种质询-响应系统,这样攻击者就无法 MitM SSL 流(当他控制移动设备时,这很容易记住)并清楚地看到秘密.

无论如何,尝试找到一个久经考验的密钥加扰机制和身份验证协议。不要自己滚动。

大多数情况下,您无法检查这是“您的应用程序”:逆向工程有效,因此任何有权访问您的应用程序的人(例如,他可以在手机上下载它)都可以提取它的内脏并用他的 PC 模拟它。@Lynks 为您提供了一些关于如何使这种逆向工程变得更令人沮丧的提示,但不要自欺欺人:如果攻击者有足够的动机,这些机制最多会使他的速度减慢几天。


当一个问题没有好的答案时,改变立场是值得的,这样问题就会改变。在这里,试图确保“您的应用程序”是在客户端运行的核心问题是存在“您的应用程序”之类的东西:如果有人打开该应用程序的内容,他会了解所有内容了解该应用程序的所有实例。

因此,这里尝试解决您的问题。用不同的值标记每个应用程序实例。这里的“标记”是指当用户下载应用程序时,会在应用程序中嵌入一些token,每次下载都会创建一个新的token值。这样每个用户都可以使用令牌获得自己的应用程序。这个想法是必须将令牌提供给您的服务器以创建帐户,如果您的服务器看到太多具有相同令牌的请求,那么它可以自动拒绝它们 - 禁止该特定令牌。

然后,为了继续自动创建许多帐户,攻击者还必须自动下载新的应用程序实例(每个都有自己的令牌值)并从下载的应用程序中检索令牌值。假设您的服务器位于应用程序下载的另一端,您还可以检测到此类大量下载并从那里阻止它。

要使此方案起作用,您必须能够按需在应用程序下载服务器上创建令牌值(但这可能很难在现有智能手机上的应用程序安装系统中进行设置),并且帐户创建服务器可以决定代币价值是否真实。HMAC是正确的加密工具。


请注意,这种解决方案远非完美。这些是为攻击者“提高标准”的游戏和技巧:如果您设计并安装了像我描述的那样的系统,那么成功的攻击者将不得不从许多不同的 IP 地址自动下载应用程序,以保持低调检测此类事物的启发式方法;然后还自动化逆向工程以恢复令牌值(使用@Lynks 解释的技术);然后将值转发给创建帐户的机器人。所有这一切在理论上仍然是可行的:毕竟,人类用户可以下载应用程序并创建帐户,而从外部来看,普通人类用户、黑猩猩和机器人之间并没有真正的区别。

但是,如果你能让攻击变得足够复杂,以至于攻击者认为它“不值得付出努力”,那么你就赢了。

如果我正在编写一个网站,我会使用 Captcha 来阻止我的数据库通过脚本填充虚假帐户。

因此,将其包含在 API 中。当用户想要创建帐户时:

  1. 客户端请求验证码。
  2. 服务器生成验证码,存储它,并将副本发送给客户端。
  3. 客户出示帐户创建表格以及验证码。
  4. 用户填写表格并回答验证码。
  5. 客户端请求创建新帐户,并随该请求发送验证码应答。

    • 如果 CAPTCHA 答案错误,服务器会删除其 CAPTCHA 副本(因此客户端无法重试)并以错误响应。

您还可以使用HashCash之类的东西来让某人更难发起暴力攻击,只要确保 HashCash 的生成速度比用户合理完成表单的速度更快。

您需要的是类似的应用程序身份验证。它与您对 Twitter、Facebook 和 Foursquare 等网站的 API 调用进行身份验证的概念相同。他们不允许任何人仅仅查询他们的 API。相反,它们会为您的应用生成 API 密钥和 API 机密。如果您的应用程序将这些密钥提供给服务器,您就可以使用它们的 API。