GraphQL:如何防止数据库刮取?

GraphQL:如何防止数据库刮取?,graphql,apollo,Graphql,Apollo,假设我在https://api.service.com/graphql用于在https://www.service.com+iOS应用程序+安卓应用程序。我想向公众公开这个API,这样第三方应用程序就可以通过查询数据在上面构建,但是我不希望他们能够刮伤我的整个数据库 假设我们有一种类型: type Thing { # public fields field1: String field2: String # fields only available in the offici

假设我在
https://api.service.com/graphql
用于在
https://www.service.com
+iOS应用程序+安卓应用程序。我想向公众公开这个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]
}
什么是只允许公司的官方用户界面查询所有
内容
字段并循环所有内容的最佳方式?应该只允许第三方开发人员在每件事情上查询
field1
field2
,并且对他们可以访问多少事情有一些限制

选择1 我考虑要求每个客户机在每个查询请求中都包含一个令牌,这样就可以检测到官方网站、iOS应用程序和Android应用程序并将其列入“白名单”。但是,如果您的javascript/应用程序包存储在客户端上,那么有什么可以阻止某人深入您的javascript/应用程序包并找到所述令牌呢

选择2 我考虑发布两个具有两个不同模式/限制集的不同API端点,例如:

https://api.service.com/graphql
-公开记录并使用有限的模式

https://api.service.com/graphql-anon
-由官方用户界面私人使用,并包含一个功能齐全/不受限制的模式


但是,还有什么能阻止用户询问应用程序包并发现
https://api.service.com/graphql-anon
端点存在并使用它来替代?

首先,我要提出一个旁白:我通常主张为您的公共API使用一个单独的模式和端点,原因有很多:

  • 清除文档。共享架构意味着某些字段或参数将无法访问,或者在使用时会抛出错误,这在查看GraphiQL/GraphQL或自省架构时可能不太明显
  • 更干净的代码。您的解析器几乎没有那么多分支逻辑,这将使它们更易于阅读和测试
  • 隐藏差异。您为“内部”API实现的功能(如缓存或分析)可能对您的公共API没有意义(并且可能会不必要地增加维护端点的成本)
  • 速率限制。您需要对公共API实施某种速率限制。如果有单独的端点,这可能会更容易做到
也就是说,显然维护两个单独的API会带来成本,因此这可能不是所有情况下都合适的解决方案

回到手头的问题。。。不管上述考虑因素如何,通常您都会使用基于令牌的身份验证来限制对所有或部分API的访问,但您不会将此令牌存储为应用程序的一部分。典型的基本流程如下所示:

  • 客户端使用用户的凭据调用某个登录端点,并返回身份验证流
  • 该令牌由客户端临时保存,并随后续每个请求一起发送到API
  • 当用户注销时,令牌将被删除
服务器使用令牌来建立用户的身份,然后可以通过请求的上下文将其提供给每个GraphQL解析器函数。这允许您仅在用户经过身份验证(或其角色允许访问该字段)的情况下有效地返回特定字段的数据。如果用户无法访问该字段,则根据类型,它只能返回null或空数组

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


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

首先,我要说的是:我通常主张为公共API提供一个单独的模式和端点,原因有很多:

  • 清除文档。共享架构意味着某些字段或参数将无法访问,或者在使用时会抛出错误,这在查看GraphiQL/GraphQL或自省架构时可能不太明显
  • 更干净的代码。您的解析器几乎没有那么多分支逻辑,这将使它们更易于阅读和测试
  • 隐藏差异。您为“内部”API实现的功能(如缓存或分析)可能对您的公共API没有意义(并且可能会不必要地增加维护端点的成本)
  • 速率限制。您需要对公共API实施某种速率限制。如果有单独的端点,这可能会更容易做到
也就是说,显然维护两个单独的API会带来成本,因此这可能不是所有情况下都合适的解决方案

回到手头的问题。。。不管上述注意事项如何,通常您都会使用基于令牌的身份验证来限制对所有或部分API的访问,但不会存储此令牌