怎样设计安全的GraphQL API?

在这篇文章,我们将讨论一些各种 GraphQL 部署和迁移的安全风险,这些安全风险在客户管理过程中被发现 。我们会讨论比较常见的高风险权限漏洞,以及不太常见的服务端请求伪造(SSRF)问题 。上述这些问题都是我们在尝试实现从 GraphQL 到 REST API 的互操作的迁移中发现的 。
除漏洞外,我们还将强调常见的错误配置和有风险的设计,来帮你避免常见错误,并为你提供一组测试用例来验证你的实现 。
语言选择很关键尽管有很多种编程语言都支持 GraphQL,但是,对一些编程语言来说,诸如社区支持库之类的工具可能比较少或者不太成熟 。
花点时间探索适合你的首选语言,并确定它们是否能满足你的长期维护需求 。
我们在这里将重点介绍 JAVAScript,因为这是我们遇到的最常见的语言 。
安全基线配置在深入讨论常见的应用程序级别漏洞前,我们先重点讨论一些应该在所有 GraphQL API 设计中实现的常见配置 。
尽管 GraphQL 的一个主要优势是它的表达式查询结构,但是由于缺乏默认约束,这种自由性也伴随着性能和可用性风险 。与所有开销大的 API 操作一样,建立安全的约束和校验配置可以减少拒绝服务攻击(DoS)的机会 。
由于这是一个老生常谈的话题,因此,我将不再深入讨论最常见的一些问题和它们已有的 JavaScript 实现方案,但我在下面将其列举出来以便在建立安全基线时进行检查:

怎样设计安全的GraphQL API?

文章插图
 
【怎样设计安全的GraphQL API?】为了检查你在这些问题上的状态,你可以问问自己下面的“安全测试用例”一节中的问题 。关于约束查询执行的深入讨论,有一篇关于《如何使一个GraphQL API 更安全》的文章很不错 。
常见安全问题既然我们已经讨论了基线配置,那我们可以进一步讨论三种常见的安全问题,这些问题在我们客户的GraphQL API 中经常看到 。
不恰当的权限控制实际上,我们在GraphQL(以及REST/SOAP API)设计中,最常见的高风险问题都与不恰当的权限控制有关,但是由于对默认解析器的过度依赖和缺乏一个集中授权层,这些问题在GraphQL 中尤其普遍 。让我们来看看一些例子:
执行基于节点的访问控制并利用授权层每个节点都应对它的数据和谁能访问它的数据进行负责 。边界检查通常是无效的,因为通常有多个边界通向给定节点 。(换句话说,仅仅因为你可以访问一个列表并不意味着你就应该能访问列表中的每一个节点 。)
此外,对默认解析器的过度依赖和不安全的默认字段可见性通常导致在开发过程中引入授权漏洞 。你可以下载 graphql-shield project来了解 GraphQL 的全功能授权层;它可以用作一个库或者作为你自己设计的灵感 。
最后,一定要研究你选择的实现中授权异常是如何处理的 。在一些案例中,异常可能泄露某个字段的存在,这可能是一个影响较大的信息泄露 。
使用可视化工具来帮助设计测试用例有一个良好的规划能让你创建授权测试用例,并开发一个清晰的访问控制系统 。在开发测试用例时,可以考虑使用如下的 GraphQL 可视化工具来识别敏感字段或节点 。
目前,最流行的工具是 GraphQL Voyager :
怎样设计安全的GraphQL API?

文章插图
 
此外,还可以试试 GraphQL Editor :
怎样设计安全的GraphQL API?

文章插图
 
经常使用用户 session 作为评估访问的唯一信源用户 session 应该是定义用户的角色或功能的唯一用户输入 。解析用户 session 并依赖它作为评估访问的唯一信源 。
我们经常看到 API 直接依赖数据库中的对象查找(例如,为了安全起见,根据无序的 UUID 查询),而不是声明请求的 session 有权限访问某个对象 。仅仅依靠对象标识符的保密性进行授权,只会创建更多机密来管理,从而给数据安全暴露更多漏洞 。
不安全的输入校验在权限之后,输入校验是我们在 GraphQL API 看到的第二常见漏洞 。不安全的输入校验包括所有经典的漏洞种类,例如 SQL 注入(SQLi)、跨站点脚本攻击(XSS)、服务端请求伪造(SSRF) 。
使用自定义标量进行强输入校验GraphQL 提供了以下内置标量类型:String、Int、Float、Boolean 和 ID(序列化为一个字符串,接受数字或字符输入) 。然而,GraphQL 也支持你自定义标量来创建自定义校验和序列化逻辑的类型(例如,DateTime类型) 。强输入和类型校验减少了来自用户输入的攻击面,是保护 API 的用户输入处理安全的第一道防线 。


推荐阅读