GraphQL - 安全 - 保护嵌套数据

GraphQL - Security - Protect nested data

假设我的应用程序是电子商务。有UsersOrdersProducts

您需要通过身份验证(使用 JWT 令牌)才能访问您的 user 数据和您的 orders。此检查在解析器中完成。

然而,Products 是 public。无需登录即可查看产品。

当然,一个UserOrders,一个OrderProducts

如果前端有人正在执行此查询怎么办:

query IAmEvil {
  products {
    orders {
      users {
         id
         name
         email
       }
    }
  }
}

这个人,未经身份验证将有权访问 users 数据。我该如何预防?

我是否必须在所有嵌套查询的所有解析器中添加规则?

相关文档:

https://www.apollographql.com/docs/guides/security.html https://www.howtographql.com/advanced/4-security/ https://blog.apollographql.com/securing-your-graphql-api-from-malicious-queries-16130a324a6b https://www.prisma.io/forum/t/graphql-security-protect-nested-data/4519

简短的回答是肯定的,但不是在嵌套的每一层。

对于任何请求,您都有用户(或缺少用户)和进入图表的路径。这与您必须授权请求的 restful 类型请求完全相同。更难的是 b/c 可以在任何地方添加解析器。

可能是关于 Facebook 如何处理此问题的最佳演讲 https://blog.apollographql.com/graphql-at-facebook-by-dan-schafer-38d65ef075af

要点是他们有一个函数负责获取和授权解析器使用。

一个可以说更优雅的解决方案是利用行级安全性 (RLS) 来控制任何特定用户可以访问哪些数据。虽然这种方法增加了一些复杂性,但如果您的 API 由具有不同角色且具有不同访问级别的用户访问,则它特别有吸引力。这实际上就是 postgraphile 处理身份验证的方式。

您还可以潜在地使用模式指令来保持内容干燥,并将一些通用访问逻辑应用于一组单独的字段。 Apollo 的文档实际上有 an example of doing just that.

除此之外,是的,您的解析器需要上下文感知并包含限制您公开的数据的逻辑。

重要的是要指出,这些问题首先也可以追溯到良好的模式设计。例如,仅仅因为关系存在并不意味着它需要(或应该)暴露给客户。一个订单可能包含一个或多个产品,如果客户端需要显示订单历史记录,那么在 Order 类型上公开一个 products 字段是有意义的。另一方面,客户真的需要知道给定产品的所有订单吗?

类似地,如果我们在 Order 上有一个 users 字段,在任何特定于用户的上下文之外,这样的字段自然只会反映关联的用户(很可能只是一个用户)与订单。将所有用户作为单个订单的字段返回是没有意义的。由于 GraphQL 的自上而下的性质,一个字段通常只限于其父级的上下文。因此,可能只需要担心根级别的用户上下文。

一个不同的任意示例:

query MyOrders {
  orders { # check context for user and limit results to just the logged in user
    user { # user will be based on parent (the order), no need to check context
      orders { # orders will be based on parent (the user), no need to check context  
      }
    }
  }
}

通过合理的架构设计,其他类型字段的解析器不一定需要进行任何额外的上下文检查。