【问题标题】:REST service and race conditionsREST 服务和竞争条件
【发布时间】:2015-05-16 02:39:07
【问题描述】:

让我们想象一个问题: 我有一个 REST 服务,它是使用 Java/MySQL/Spring 和 HTTP/JSON 技术实现的。 REST 服务的客户端是移动应用程序。 所以很有可能有人会反编译代码,得到REST服务的API。 (是的,代码被混淆了等,但无论如何)。

问题:有一个 POST 方法可以向应用程序的其他用户汇款。 我很担心,有人可以获得 API,编写一个机器人,然后每秒发出 500 或 5,000 甚至 50,000 次 POST 请求。 结果,他发送的钱可能比他实际拥有的多,因为如果同时处理 1000 个请求,那么余额检查可能是 所有 1000 个请求都成功,但是帐户上的实际金额可能仅够 50 个请求。

因此,基本上,它更像是具有多个线程的标准“竞争”条件。 问题是,我有多个服务器,无论如何它们彼此无关。 所以,300个请求可以到达服务器A,300个请求可以到达服务器B,其余请求可以到达服务器C。

我最好的办法是使用“SELECT ... FOR UPDATE”之类的东西并在数据库级别进行同步。 不过,我想考虑另一种解决方案。

有什么想法或建议吗?

【问题讨论】:

  • 您没有登录、会话和反 csrf 令牌来确保传输请求只能来自已登录的授权用户吗?您是否没有授权检查以确保仅尊重转移自己资金的请求?你不是有一个三层应用程序,所以前端只处理表示层,而业务逻辑在幕后处理?您是否无法在单个业务逻辑服务器中对类似请求(相同的捐赠者、相同的目标等)进行分段处理?
  • 登录/会话如何防止这种情况?如果有人破解 API,他可以破解登录/会话并使用有效的身份验证机制发送此请求。顺便说一下,身份验证是基于令牌的,即 OAuth。这是一个 REST 服务,我不使用 csrf 令牌。
  • 如果您让人们登录并限制某些东西,使人们只能花费自己的钱,那么您可以防止攻击者花费别人的钱的攻击。这并不能防止他们透支自己的帐户,但确实可以防止他们透支别人的帐户。
  • 您可能还想调查透支费用,就像银行一样...

标签: java rest race-condition


【解决方案1】:

你有几个选择:

  1. 依赖数据库的 ACID 实现(在您的情况下为 MySQL)。假设您使用的是 InnoDB 引擎,您需要结合正确的锁定读取机制 (SELECT ... FOR UPDATE and SELECT ... LOCK IN SHARE MODE Locking Reads) 选择正确的事务隔离级别 (SET TRANSACTION syntax)。您需要很好地理解这些概念才能做出正确的选择。即使没有锁定读取,简单地使用正确的隔离级别也可能已经阻止了竞争条件。缺点是您正在权衡一致性以换取可伸缩性,并将您的应用程序绑定到 RDBMS 数据库,因此您将更难以迁移到 NoSQL。

  2. 将后端分解为 Web 层和服务层(atk 在 cmets 中建议的选项)。这将允许您独立扩展 Web 层实例,同时保留单个服务层实例。拥有单个服务层实例可以使用 Java 同步机制,例如 synchronised 块或 ReadWriteLock。尽管此解决方案可行,但我不推荐它,因为它会降低服务层的可扩展性。

  3. 这是对上一个选项的增强。您可以使用Distributed lock manager 代替内置的java 同步机制。它将允许您独立扩展 Web 层和服务层。

【讨论】:

  • 感谢您的回答 :) 分布式锁管理器对于可扩展性来说可能不是一个好主意。我会尝试使用 RDBMS。
【解决方案2】:

对于任务关键型应用程序,最好有多个级别的锁定机制。

"SELECT ... FOR UPDATE" 是一个很好的方法,但它们非常昂贵,当你尝试用 Charles 轰炸它时,你会发现你的上层 API 堆栈会受到影响,而且简单的机制很容易破坏您的基础设施,就像 DDoS 事件一样。

首先在负载均衡器/代理层实现它,以限制来自单个 IP 地址的每个指定时间间隔的 N 次请求。

然后应用共享缓存层锁定,根据您要锁定的关键事务,您所有的盒子都会在某些键上同步。例如,您可以在进入关键代码路径之前使用 Redis GETSET 或 INCR 功能自动设置标志。快速拒绝其他任何东西,以避免那些不良行为者持有 CPU/内存。

您还可以实现 APC 缓存(在访问您的 Redis / Memcache 集群之前)之类的东西,以在每个盒子的基础上进行类似的锁定。由于不涉及网络延迟,因此速度更快。

以上是使用“SELECT ... FOR UPDATE”的必要条件

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-10
    • 1970-01-01
    • 2020-07-12
    • 2017-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多