GraphQL - 安全性 - 保护嵌套数据

3
假设我的应用程序是一个电子商务平台。有 Users, OrdersProducts
要访问你的user数据和你的orders,你需要进行身份验证(使用JWT令牌)。这个检查是在解析器中完成的。
然而,Products是公开的。你可以在未登录的情况下查看产品。
当然,UserOrders,而OrderProducts
如果前端有人执行此查询,会怎样呢?
query IAmEvil {
  products {
    orders {
      users {
         id
         name
         email
       }
    }
  }
}

这个人没有经过身份验证,就可以访问“用户”数据。我该怎么防止这种情况发生?
我是否需要为所有嵌套查询的解析器添加规则?
相关文档:

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

2个回答

4

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

您还可以潜在地使用模式指令来保持DRY并将一些通用访问逻辑应用于一组单独的字段。Apollo的文档实际上有一个执行此操作的示例

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

需要指出的是,这些问题也与首先进行良好模式设计有关。例如,仅因为存在关系并不意味着需要(或应该)将其暴露给客户端。一个订单可能包括一个或多个产品,如果客户需要显示订单历史记录,则在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  
      }
    }
  }
}

通过良好的模式设计,其他类型字段的解析器不需要进行任何额外的上下文检查。

请问您能详细说明如何实现RLS吗?如果我理解正确,这应该在数据库层面上完成,这是否意味着您需要根据用户(授权)组在数据库中建立不同的连接? 阿波罗文档的第二个链接已失效。 - cglacet

1
简短的回答是可以,但并非每个嵌套层级都是如此。对于任何请求,您都需要用户(或缺乏用户)和进入图形的路径。这与需要授权请求的restful类型请求完全相同。不过,它更难,因为解析器可以添加到任何位置。Facebook处理此问题的最佳方法可能在此处https://blog.apollographql.com/graphql-at-facebook-by-dan-schafer-38d65ef075af中讲述。要点是他们有一个负责获取和授权解析器使用的函数。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接