首页 文章

Dogfooding我们自己的速率限制API

提问于
浏览
116

Overview:

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

  • 答:围绕我们的产品创建强大的开发者生态系统 .

  • B:通过使用它来驱动我们自己的应用程序,展示我们API的强大功能 .

澄清:为什么要限价?

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

The Problem:

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

所以问题是:

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

Explored Solutions (and why they didn't work)

  • 根据主机头验证引用者 . - 有缺陷,因为 referrer 很容易被伪造 .

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

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

The Question:

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

9 回答

  • 9

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

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

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

  • 8

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

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

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

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

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

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

    • 确保您的限制针对您要删除的滥用行为采取合理的行动 . 例如,考虑排队或推迟轻度滥用者而不是拒绝连接 . 大多数Web前端只会同时打开四个同时连接 . 如果你推迟尝试打开五分之一,你只会遇到他们正在使用的情况与Web客户端(两个Web客户端)同时使用CLI . 如果你延迟第n个API调用没有间隙而不是失败,最终用户会看到事情变慢而不是中断 . 如果将此结果与仅一次排队的N API调用结合使用,您只会遇到并行处理大量API调用的人,这可能不是您想要的行为 - 例如同时进行100次API调用,一小时的差距通常比一小时内的100次连续API调用差得多 .

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

  • 33

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

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

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

  • 2

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

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

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

  • 11

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

    Pick another way to demonstrate the power of your API. 例如,编写这样的应用程序并共享其源代码,但实际上并不运行该代码 . 确保它已被充分记录,以便任何人都可以部署它并看到它正常工作(受限制) .

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

    Adjust rate limitation 允许您的应用程序工作并投入性能优化来处理负载 .

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

  • 4

    您是否可以站出一个单独的UI实例和无限制API,然后限制对来自您组织的IP地址的访问?

    例如,如果需要在实例之间共享数据,则将整个事物部署在公司防火墙后面,并将应用程序附加到与面向公众的实例相同的数据库 .

  • 4

    您可以尝试生成唯一的会话ID,绑定到某个IP地址/用户以及有限的生存时间 . 当用户下载您的应用程序前端JavaScript时代码将生成的会话ID注入JavaScript源代码 . 会话ID将附加到API的每个请求,并取消速率限制 .

    无法简单地复制ID以进行欺骗,因为它仅对单个IP地址,用户和有限的时间有效 . 因此,攻击者必须调用您的页面并从JavaScript源中过滤掉密钥,或者在每次新用户想要使用它时拦截Ajax请求 .

    Another Option:

    为您自己的应用程序设置代理并使用模糊处理 . 对代理的Ajax请求使用与真实API调用不同的名称,代理将它们转换回来 . 因此,您的应用程序不会在您的真实API上调用 getDocument ,但它会在您的代理上调用 getFELSUFDSKJE . 代理会将此调用转换回getDocument并将其转发给实际的速率限制API .

    您的实际API不会对代理的请求进行速率限制 .

    因此,其他人不会将您的代理用于他们自己的应用程序,您每天都会更改混淆方案 . 模糊的调用名称可以在JavaScript源代码中自动生成,并在代理中进行配置 .

    希望使用此功能的客户还需要跟上您不断变化的混淆以使用您的代理 . 您仍然可以使用referrer-headers和类似的日志记录,因此您可以找到使用您的代理的人 . 或者在更改混淆方案时捕获它们 .

  • 3
    • 白名单源IP地址

    • 使用VPN,白名单VPN成员

    • 添加HTTP标头的代理解决方案或浏览器插件应该没问题,如果您可以保护代理并且不关心MITM攻击嗅探流量

    • 任何涉及秘密的解决方案都可以通过每天轮换秘密来减轻泄漏的影响

  • 93

    设置多个帐户,并在每次请求时随机选择其中一个帐户,或者更改每小时左右使用的帐户 . 通过这种方式,您可以在 n 帐户上分配负载,最多可以达到 n 倍的限制 .

    如果您试图找到其他用户这样做,如果客户不允许,请小心不小心关闭自己 .

相关问题