【问题标题】:GraphQL: How to prevent nesting attack to gain access to unauthorized data?GraphQL:如何防止嵌套攻击以访问未经授权的数据?
【发布时间】:2020-01-18 09:36:32
【问题描述】:

我正在运行 AWS AppSync GraphQL API 服务,尽管根据我所知道的,这个问题同样适用于 apollo-server。

根据我对 GraphQL 解析器及其链接方式的理解,恶意授权客户端似乎可以针对他们有权访问的对象发出经过身份验证的请求,然后在正文中将请求链接在一起,以便最终访问它们不属于的记录授权给。 有哪些有效的设计模式可以防止此类攻击

例如,我将使用一个不是我实际的情况,但应该足够简单以理解我的意思。假设我们正在运行一个学生成绩数据库。

有称为学生、成绩和课程的类型。

为方便起见,当您查找学生时,其中有一个解析器可返回成绩。同样为方便起见,当您查找成绩时,它所在的课程有一个解析器。另外,为方便起见,当您查找课程时,您可以看到已注册的学生。

现在,作为一名学生,我完全有理由这样称呼:

query {
  getMyRecord {
    name
    studentId
    ssn
    grades {
      gradeValue
      semester
      course {
        name
        courseId
        courseNumber
      }
    }
  }
}

这将是一个非常正常的电话。此外,GraphQL API 也支持课程管理员和教授的方法,因此他们完全有权调用类似的方法:

query {
  getCourse {
    name
    courseId
    courseNumber
    students {
      studentId
      name
    }
  }
}

同样,我们的 GraphQL API 支持非常合理。

问题是恶意学生可能会检查架构并决定将上面的第一个查询扩展为:

query {
  getMyRecord {
    name
    studentId
    ssn
    grades {
      gradeValue
      semester
      course {
        name
        courseId
        courseNumber
        students { #note here!
          name
          ssn
          grades {
            gradeValue
            #... and so on!
          }
        }
      }
    }
  }
}

这将导致恶意开始查看其他学生的成绩和 ssn、他们正在学习的课程、学生在 THOSE 课程中注册的内容等等。

我可以想到一些设计模式来防止这种情况,但它们似乎都不优雅。特别是,我可以在链式解析器的每一步都重新运行授权器,但这会导致工作量大幅增加,99% 的调用会出现大量重复工作。

我非常期待学习已建立的设计模式以防止此类攻击。

【问题讨论】:

    标签: amazon-web-services security graphql aws-appsync


    【解决方案1】:

    在大多数 GraphQL 框架中,授权是在字段级别处理的。您通过上下文对象将用户和/或其角色和权限注入您的解析器,然后在解析器本身中包含任何授权逻辑。像 graphql-shield 这样的流行库可以提供更好的方法来实现这一点,并且更容易创建可重用的规则 - 但是,归根结底,它仍然是相同的想法。

    这里的关键是,此授权逻辑不仅应适用于您的根级别字段,还应适用于表示数据中关系的其他字段(例如您示例中的 students 字段)。

    我不使用 AppSync,但我相信 the docs 广泛描述了如何在这种情况下应用这种模式。

    另一种方法是在域或存储层处理授权。例如,PostGraphile 利用行级安全性来强制执行授权规则。这可以让您在 node 级别实现授权(用户可以访问哪些资源,而不是哪些字段)。

    【讨论】:

      【解决方案2】:

      我不知道您使用的是哪种类型的授权,但您可以使用context variables 设置条件。如果您使用 AWS_IAMAMAZON_COGNITO_USER_POOLS 授权,则您有来自上下文的username,您可以根据username 返回响应。例如,在您的 students 解析器映射响应中,您可能有:

      {
         #if($context.result["username"] == "$context.identity.username")
            $utils.toJson($context.result);
         #end
      }
      

      如果username 与此检查不匹配,则仅返回空响应。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-09-17
        • 2012-01-14
        • 2015-04-03
        • 2019-03-23
        相关资源
        最近更新 更多