GraphQL - 安全 - 保护嵌套数据
GraphQL - Security - Protect nested data
假设我的应用程序是电子商务。有Users
、Orders
和Products
。
您需要通过身份验证(使用 JWT 令牌)才能访问您的 user
数据和您的 orders
。此检查在解析器中完成。
然而,Products
是 public。无需登录即可查看产品。
当然,一个User
有Orders
,一个Order
有Products
如果前端有人正在执行此查询怎么办:
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
}
}
}
}
通过合理的架构设计,其他类型字段的解析器不一定需要进行任何额外的上下文检查。
假设我的应用程序是电子商务。有Users
、Orders
和Products
。
您需要通过身份验证(使用 JWT 令牌)才能访问您的 user
数据和您的 orders
。此检查在解析器中完成。
然而,Products
是 public。无需登录即可查看产品。
当然,一个User
有Orders
,一个Order
有Products
如果前端有人正在执行此查询怎么办:
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
}
}
}
}
通过合理的架构设计,其他类型字段的解析器不一定需要进行任何额外的上下文检查。