【问题标题】:GraphQL: How to Prevent Database Scraping?GraphQL:如何防止数据库抓取?
【发布时间】:2019-03-24 19:43:11
【问题描述】:

假设我在 https://api.service.com/graphql 有一个 graphql 端点,用于在 https://www.service.com + 一个 iOS 应用 + 一个 Android 应用上构建公司的官方 UI。我想向公众公开这个 API,以便第三方应用程序可以通过查询数据在它之上构建,但是我不希望他们能够抓取我的整个数据库。

假设我们有一个类型:

type Thing {
  # public fields
  field1: String
  field2: String

  # fields only available in the official UI
  field3: String
  field4: String
}

还有一个查询:

{
  things(limit: Int!, offset: Int): [Thing]
}

只允许公司的官方 UI 查询所有 Thing 字段并遍历所有内容的最佳方法是什么?应该只允许第三方开发者在每个事物上查询field1field2,并且对他们可以访问多少事物有一些限制。

选项 1

我想过要求每个客户端在每个查询请求中都包含一个令牌,以便可以检测到官方网站、iOS 应用和 Android 应用并将其“列入白名单”。但是,如果它存储在客户端上,什么会阻止有人深入研究您的 javascript / 应用程序包并找到所述令牌?

选项 2

我考虑过发布两个不同的 API 端点,它们具有两个不同的架构/限制集,例如:

https://api.service.com/graphql - 公开记录并使用有限的架构。

https://api.service.com/graphql-anon - 由官方 UI 私下使用,包含全功能/不受限制的架构。

但同样,什么会阻止用户询问应用程序的捆绑包并发现 https://api.service.com/graphql-anon 端点存在并改为使用它?

【问题讨论】:

    标签: graphql apollo


    【解决方案1】:

    首先,顺便说一句:出于多种原因,我通常会主张为您的公共 API 使用单独的架构和端点:

    • 清晰的文档。共享架构意味着某些字段或参数将无法访问,或者在使用时会引发错误,这在查看 GraphiQL/GraphQL Playground 或内省架构时可能不太明显。
    • 更简洁的代码。您的解析器几乎没有那么多分支逻辑,这将使它们更易于阅读和测试。
    • 内部差异。 您为“内部”API 实现的某些功能(如缓存或分析)可能对您的公共 API 没有意义(并且可能会不必要地增加成本)维护端点)。
    • 速率限制。您需要为公共 API 实施某种速率限制。如果您有单独的端点,这可能会更容易做到。

    也就是说,显然维护两个单独的 API 会产生成本,因此这可能不是在所有情况下都适合的解决方案。

    回到手头的问题...不管上述考虑如何,通常您会使用基于令牌的身份验证来限制对您的全部或部分 API 的访问,但您不会将此令牌存储为您的应用程序的一部分.一个典型的基本流程是这样的:

    • 客户端使用用户凭据调用某个登录端点并返回身份验证流程
    • 令牌由客户端临时保存,并与每个后续请求一起发送到 API
    • 当用户注销时,令牌被删除

    服务器使用令牌来建立用户的身份,然后可以通过请求的上下文将其提供给每个 GraphQL 解析器函数。如果用户经过身份验证(或者如果她的角色允许访问该字段),这允许您有效地仅返回特定字段的数据。如果用户无法访问该字段,它可以只返回 null 或空数组,具体取决于类型。

    当然,您还可以为未经身份验证的用户提供一小部分查询。这种方法允许您根据角色拥有不同级别的访问权限(因此“管理员”用户可能比“标准”用户拥有更多查询或字段的访问权限,后者比未经身份验证的用户拥有更多访问权限)。

    在公共 API 的情况下,您可以使用客户端令牌的某种组合以类似的方式识别第三方客户端(也许他们不必登录,但使用令牌的哈希值和您的秘密例如,在注册时分配给他们)。如果您有一个共享模式,则可以支持这两种身份验证机制。通过这种方式,“第三方客户端”可以只是另一个可以访问某些字段子集的角色。

    【讨论】:

    • 感谢您的详细解释。如果我要使用单独的 API 进行公共访问,您对如何保护“内部”API 不被发现/滥用有任何建议/建议吗?这是我对上述选项 2 的担忧。
    • 您仍然希望如上所述实现身份验证和限制访问。您可以实施自定义身份验证标头和速率限制以阻止滥用,但我不相信实际上您可以拥有可通过 Internet 访问的 API 并限制仅对您的客户端的访问。
    • 谢谢丹尼尔。在我的官方 UI 中,我希望匿名用户能够查询几乎与登录用户一样多的数据。那么,当您不必必须登录/创建身份验证令牌以使用应用程序的 90% 时,我将如何检测/限制某人?
    • 您可能需要考虑要求登录,即使它通过 Google 或 Facebook 等提供商使用 SSO。除此之外,您可以让客户端根据正在使用的设备发送某种唯一标识符(有像 device-uuid 这样的库来做这种事情客户端)。
    • 维护客户端和/或会话的内部配置文件,这将它们视为普通人与试图抓取的机器人。这可以通过各种工具来完成,例如前端的间歇性验证码检查,或观察/记录浏览模式。最后,它永远不会 100%,但可以让你接近。
    猜你喜欢
    • 2013-12-22
    • 2012-12-30
    • 1970-01-01
    • 2021-01-23
    • 2010-11-29
    • 1970-01-01
    • 2021-12-07
    • 2014-01-30
    • 1970-01-01
    相关资源
    最近更新 更多