Dogfooding我们自己的速率限制API

Jas*_*rip 116 javascript api rest

概述:

我公司开发了一个限速API.我们的目标是双重的:

  • 答:围绕我们的产品创建强大的开发者生态系统.
  • B:通过使用它来驱动我们自己的应用程序,展示我们API的强大功能.

澄清:为什么要限价?

我们限制我们的API,因为我们将其作为产品的补充销售.对我们的API的匿名访问每小时API调用的门槛非常低,而我们的付费客户每小时允许超过1000个呼叫或更多.

问题:

我们的速率限制API非常适合开发人员生态系统,但为了让我们食用它,我们不能将它限制在相同的速率限制范围内.我们API的前端是所有JavaScript,直接对API进行Ajax调用.

所以问题是:

如何保护api,以便在移除速率限制的过程中可以消除速率限制,不能轻易欺骗?

探索的解决方案(以及他们为什么不工作)

  1. 根据主机头验证引用者.- 有缺陷,因为推荐人很容易伪造.

  2. 使用HMAC根据请求和共享密钥创建签名,然后在服务器上验证请求.- 有缺陷,因为通过查看前端JavaScript可以轻松确定秘密和算法.

  3. 代理请求并在代理中签署请求 - 仍然存在缺陷,因为代理本身公开了API.

问题:

我期待Stack Overflow上出色的思想提出替代解决方案.你会如何解决这个问题?

Kri*_*ján 93

由于您自己的JavaScript客户端直接访问API,因此任何人都可以查看它正在做什么并模仿它,包括使用相同的API密钥.您可以尝试使其变得更加困难,例如通过混淆代码或在路上设置各种障碍,但是您和您试图约束的人基本上具有相同的访问权限.您不需要尝试创建权限差异,而是需要构建一个系统,非官方客户端使用其范围内的所有访问权限,但系统的安排方式使得所有客户端的正式使用是更大.

这通常使用每用户访问令牌来完成,而不是整个应用程序的一个令牌.对于典型的API使用,每个令牌的限制应该很多,但对于试图滥用它的人来说则是限制性的.例如,每分钟100次呼叫可能足以支持典型的浏览,但如果我想抓住你,我就无法在预算上有效地做到这一点.

将永远存在军备竞赛 - 我可以通过创建大量的僵尸用户帐户来绕过极限.但是,如果你只是在你的注册流程中添加一个验证码,那么这是一个非常好的解决问题,只需花费一小部分费用给真正的人类.当你进入这些场景时,一切都只是在便利和限制之间进行权衡.你永远不会找到完全防弹的东西,所以要专注于使它足够好并等到有人利用你去了解洞的位置.

  • 接受这个作为最佳答案.我们决定采用的路线是使用较低过期的JWT令牌并增加这些呼叫的速率限制.我们将在令牌中编码一些额外的信息,让后端知道更高的速率限制.由于这些令牌在后端安全签名,因此欺骗应该没有问题.有人仍然可以使用该令牌,但它会在几天后过期,因此维持任何类型的机器人都会更难. (8认同)

abl*_*igh 33

如果这导致您出现问题,则会导致您假定的开发人员生态系统出现问题(例如,当他们尝试开发替代UI时).如果你真的在吃自己的狗粮,那么API(以及速率限制)适合你的应用.以下是一些建议:

  • 不要按IP地址限制速率.而是通过与用户相关联的事物来限制速率,例如他们的用户ID.在身份验证阶段应用速率限制.

  • 设计您的API,以便用户不需要连续调用它(例如,给出一个返回许多结果的列表调用,而不是每次返回一个项目的重复调用)

  • 使用您期望开发人员生态系统具有的相同约束来设计您的Web应用程序,即确保您可以在合理的限制速率内进行设计.

  • 确保您的后端是可伸缩的(水平优选),因此您不需要在如此低的级别上施加限制,这实际上会导致UI出现问题.

  • 确保您的节流能够应对爆发,并限制长期滥用.

  • 确保您的节流针对您要删除的滥用行为进行合理的行动.例如,考虑排队或推迟轻度滥用者而不是拒绝连接.大多数Web前端只会同时打开四个同时连接.如果您延迟尝试打开第五个,您只会遇到他们与Web客户端(两个Web客户端)同时使用CLI的情况.如果你延迟第n个API调用没有间隙而不是失败,最终用户会看到事情变慢而不是中断.如果你只将它与一次排队的N API调用结合起来,那么你只会遇到那些并行化大量API调用的人,这可能不是你想要的行为 - 例如,100个同时的API调用然后一小时的差距通常是远的超过一个小时的100次连续API调用.

这不能回答你的问题吗?好吧,如果你真的需要做你想要的,在认证阶段限速,并根据你的用户适合的组应用不同的速率限制.如果您使用一组凭据(由您的开发人员和QA团队使用),则会获得更高的速率限制.但是你可以立即明白为什么这将不可避免地导致你的生态系统看到你的开发和QA团队看不到的问题.


jkd*_*dev 11

购买你的产品.成为自己的付费客户.

"对我们的API的匿名访问每小时API调用的门槛非常低,而我们的付费客户每小时或更长时间允许超过1000次呼叫."

这也有助于从客户的角度测试系统.


Mic*_*yan 9

不幸的是,没有完美的解决方案.

一般方法通常是为客户端提供一种可欺骗的方式来标识自己(例如,标识符,版本和API密钥 - 例如),以便客户端注册可用于限制访问的自身信息(例如,客户端是给定IP地址范围内的服务器,因此只允许该范围内的调用者;例如,客户端是JavaScript,但仅传递给特定类别的浏览器,因此只允许访问指定某些用户代理字符串的HTTP请求;等等) ,然后使用机器学习/模式识别来检测可能是欺骗客户端的异常使用,然后拒绝来自这些欺骗客户端的流量(或与客户确认这些用法确实不是来自合法客户端,替换他们的可欺骗凭据,然后使用旧的欺骗凭证禁止进一步的流量.

通过使用多层密钥,您可以使欺骗变得更加困难.例如,您提供一个存在于服务器上的长寿凭证(并且只能在一组有限的IP地址范围内使用)来进行API调用,以记录有关客户端的信息(例如用户代理)和返回一个生命周期较短的客户端密钥,该密钥在JavaScript中进行联合,以便在客户端用于客户端API请求.这也是不完美的(欺骗者可以发出相同的服务器调用来获取凭证),但如果返回的API密钥包含在混淆(且经常变化)的JavaScript或HTML中(这将使其变得困难)将会更加困难从响应中可靠地提取).这也提供了一种更容易检测欺骗的方法; 客户端密钥现在绑定到特定客户端(例如特定用户代理,甚至可能是特定的cookie jar),这使得在另一个客户端中重用易于检测,并且到期还限制了可以重用欺骗密钥的持续时间.


Ant*_*off 8

假设有问题的应用程序必须公开,您没有太多选择:

选择另一种方式来演示API的强大功能.例如,编写这样的应用程序并共享其源代码,但实际上并不运行该代码.确保它已被充分记录,以便任何人都可以部署它并看到它正常工作(受限制).

您运行的应用程序需要进行重构,以避免客户端API请求并提供更多服务器呈现.你仍然可以对你的API进行dogfood,但不是以明显的方式 - 从服务器端向无限制的API发出安全请求.

调整速率限制以允许您的应用程序工作并投资于性能优化以处理负载.

是的,首先让核心API无油门,并将其保存在专用网络中.在单独的可公开访问的层中进行节流.