发布在即!企业 AIGC 应用程度测评,3 步定制专属评估报告。抢首批测评权益>>> 了解详情
写点什么

怎样设计安全的 GraphQL API?

  • 2020-10-22
  • 本文字数:3919 字

    阅读完需:约 13 分钟

怎样设计安全的GraphQL API?

在这篇文章,我们将讨论一些各种 GraphQL 部署和迁移的安全风险,这些安全风险在客户管理过程中被发现。我们会讨论比较常见的高风险权限漏洞,以及不太常见的服务端请求伪造(SSRF)问题。上述这些问题都是我们在尝试实现从 GraphQL 到 REST API 的互操作的迁移中发现的。


除漏洞外,我们还将强调常见的错误配置和有风险的设计,来帮你避免常见错误,并为你提供一组测试用例来验证你的实现。

语言选择很关键

尽管有很多种编程语言都支持 GraphQL,但是,对一些编程语言来说,诸如社区支持库之类的工具可能比较少或者不太成熟。


花点时间探索适合你的首选语言,并确定它们是否能满足你的长期维护需求。


我们在这里将重点介绍 JavaScript,因为这是我们遇到的最常见的语言。

安全基线配置

在深入讨论常见的应用程序级别漏洞前,我们先重点讨论一些应该在所有 GraphQL API 设计中实现的常见配置。


尽管 GraphQL 的一个主要优势是它的表达式查询结构,但是由于缺乏默认约束,这种自由性也伴随着性能和可用性风险。与所有开销大的 API 操作一样,建立安全的约束和校验配置可以减少拒绝服务攻击(DoS)的机会。


由于这是一个老生常谈的话题,因此,我将不再深入讨论最常见的一些问题和它们已有的 JavaScript 实现方案,但我在下面将其列举出来以便在建立安全基线时进行检查:



为了检查你在这些问题上的状态,你可以问问自己下面的“安全测试用例”一节中的问题。关于约束查询执行的深入讨论,有一篇关于《如何使一个GraphQL API更安全》的文章很不错。

常见安全问题

既然我们已经讨论了基线配置,那我们可以进一步讨论三种常见的安全问题,这些问题在我们客户的 GraphQL API 中经常看到。

不恰当的权限控制

实际上,我们在 GraphQL(以及 REST/SOAP API)设计中,最常见的高风险问题都与不恰当的权限控制有关,但是由于对默认解析器的过度依赖和缺乏一个集中授权层,这些问题在 GraphQL 中尤其普遍。让我们来看看一些例子:

执行基于节点的访问控制并利用授权层

每个节点都应对它的数据和谁能访问它的数据进行负责。边界检查通常是无效的,因为通常有多个边界通向给定节点。(换句话说,仅仅因为你可以访问一个列表并不意味着你就应该能访问列表中的每一个节点。)


此外,对默认解析器的过度依赖和不安全的默认字段可见性通常导致在开发过程中引入授权漏洞。你可以下载graphql-shield project来了解 GraphQL 的全功能授权层;它可以用作一个库或者作为你自己设计的灵感。


最后,一定要研究你选择的实现中授权异常是如何处理的。在一些案例中,异常可能泄露某个字段的存在,这可能是一个影响较大的信息泄露。

使用可视化工具来帮助设计测试用例

有一个良好的规划能让你创建授权测试用例,并开发一个清晰的访问控制系统。在开发测试用例时,可以考虑使用如下的 GraphQL 可视化工具来识别敏感字段或节点。


目前,最流行的工具是GraphQL Voyager



此外,还可以试试GraphQL Editor:


经常使用用户 session 作为评估访问的唯一信源

用户 session 应该是定义用户的角色或功能的唯一用户输入。解析用户 session 并依赖它作为评估访问的唯一信源。


我们经常看到 API 直接依赖数据库中的对象查找(例如,为了安全起见,根据无序的 UUID 查询),而不是声明请求的 session 有权限访问某个对象。仅仅依靠对象标识符的保密性进行授权,只会创建更多机密来管理,从而给数据安全暴露更多漏洞。

不安全的输入校验

在权限之后,输入校验是我们在 GraphQL API 看到的第二常见漏洞。不安全的输入校验包括所有经典的漏洞种类,例如 SQL 注入(SQLi)、跨站点脚本攻击(XSS)、服务端请求伪造(SSRF)。

使用自定义标量进行强输入校验

GraphQL 提供了以下内置标量类型:String、Int、Float、Boolean 和 ID(序列化为一个字符串,接受数字或字符输入)。然而,GraphQL 也支持你自定义标量来创建自定义校验和序列化逻辑的类型(例如,DateTime类型)。强输入和类型校验减少了来自用户输入的攻击面,是保护 API 的用户输入处理安全的第一道防线。


当实现自定义标量时,考虑使用旨在定义通用自定义标量的开源库并进行贡献。这能帮助每个团队减少开发他们自己的校验逻辑所需的时间和精力,还可以帮助每个人避免重复相同错误。下面是两个现有的致力于创建共享自定义标量库的项目:



Urigo 的项目包含一个校验正则标量的基础模板,它简化了将现有的正则表达式从 REST API 到自定义标量的转变:


避免自定义标量封装其它类型(JSON/XML)

避免创建复杂类型的自定义标量,例如 JSON(例如graphql-type-json)。


复杂的自定义标量会妨碍嵌套类型的正确校验,还可能引入漏洞,例如 GraphQL 查询注入或 NoSQL 注入。对于这些风险,我们会在下一节进行详细讨论。

其它转换和缓存问题

大部分 GraphQL 实现是引入到现有的 REST 生态系统的。


在本节,我们将检查你在转换过程中可能遇到的风险。GraphQL 和 REST 之间的转换过程,结合缓存,它会导致各种不可预知的漏洞。

REST 和 GraphQL 之间转换时避免输入校验问题

REST 转 GraphQL

假设我们引入了一个新的 GraphQL 后端服务来支持对一个现有的 REST API 网关的数据检索。为了查询 GraphQL 服务,我们的开发者可能会尝试将传入的查询参数插入到一个后端 GraphQL 请求中:


userUpdateQuery = `mutation {       updateUser(       firstName: "${request['firstname']}",       lastName: "${request['lastname']}",       ) {           User {               firstName               lastName           }     }   }`;
复制代码


传统的 REST API 可能是弱类型的(GET/POST 参数)或者强类型的(JSON/XML),这使得转换成一个强类型 API 容易出错。例如,当尝试这样转换时,有很多机会向查询中注入额外的 JSON 语句。


为减少这些风险,可以考虑使用持久化查询。持久化查询允许你将一个哈希值对应于一个存储的服务器端查询及其输入变量。这将安全插值委托给库,限制了构建请求时的查询注入机会。

GraphQL 转 REST

作为我们迁移策略的一部分,假设我们在现有的 REST API 前面放一个 GraphQL 服务。


那么,针对我们的 GraphQL API 的服务器端解析函数可能会使用用户提供的如下文件名参数来执行访问某个内部 REST API 的内部 GET 请求:


let myFile = await axios.get(`https://api.product.int/file/${args.filename}`);
复制代码


通过提交一个路径遍历负载作为参数,攻击者能控制外部的 API 请求来执行恶意行为(例如,../user/setRoles?roles=[admin,user])。这只是会导致 SSRF 的不安全查询构建的一个例子;任何时候,外部请求中的用户输入都是有风险的。


这种转换可能更有挑战性,因为用户输入需要被清理两次:在 GraphQL 前端,对用于外部请求的查询构建中使用的数据进行额外清理,然后在 REST 后台服务中再次清理。


确保所有查询参数都针对它们将放入的请求上下文进行了清理(例如,路径参数的 URI 语法和 JSON 信息的 JSON 语法)。尽可能依赖标准库。

在引入中间缓存时避免破坏授权

一些 GraphQL 实现会去除现有后端 REST 基础设施的所有授权。这在为现有 REST API 创建一个 GraphQL 网关时特别常见。然而,由于这会导致额外的延迟,所以常见的是在 GraphQL 服务器和 REST API 服务器之间引入中间缓存。然而,与转换带来的风险类似,这种方案也会导致问题。


如果授权过的响应保存在缓存中,未经授权的请求可能会不恰当地获取到缓存的内容,而无需到后端 REST 服务器进行授权检查。由于授权逻辑位于中间缓存层后面,GraphQL 服务器需要处理缓存检索逻辑来确保不会违反后端访问控制。

安全测试用例

既然我们已经对迁移过程中可能遇到的问题和犯的错误有了一个很好的理解,那么,我们可以定义一个测试用例列表:


  • introspection 在生产环境被禁用了吗?

  • 速率限制:

  • ​ 1. 有查询速率限制吗?

  • ​ 2. 有查询深度限制吗?

  • ​ 3. 有响应限制(例如,能否分页)吗?

  • ​ 4. 有查询复杂度限制吗?

  • 授权:

  • ​ 1. 查询在节点层次有恰当的访问控制吗?

  • ​ 2. 所有数据的访问路径都保持相同的访问控制吗?

  • ​ 3. 对于只有部分角色才能访问的字段,这些访问控制是强制的吗?

  • ​ 4. 不同的错误响应是否泄露了字段或节点的存在?

  • ​ 5. 源代码:授权检查是否依赖单一信源(例如,用户的 session);代码对非白名单字段是否有回退拒绝规则?

  • ​ 6. 输入校验:API 是否执行强输入校验(例如,有限制的整数值或者名称的有限字符集);API 是否正确处理了 null 值;当向输入中注入常见的 SQL(例如,[‘][--][#])或 GraphQL(例如,JSON)语句时,服务器端是否会报错?

  • ​ 7. 转换和缓存:GraphQL 到 REST:当注入特定 URI 字符时,REST API 会报错吗;REST 到 GraphQL:当向前端 REST API 的查询参数提交 JSON 语句时,GraphQL 会报错吗;缓存:当快速提交请求时,会出现预期之外的现象吗?两个独立的用户账户快速提交请求又会怎么样呢?


本文没有讨论以下日志测试用例,但也值得考虑:


  • 服务器端日志是否跟踪相关 session 和操作名?你能确定与恶意请求相关的用户吗?

  • 当发生开销大的查询或其它异常时,你是否记录?

结论

我们在本文讨论了各种常见的 GraphQL bug,但是在特定部署上下文中,它会出现更多的 bug;错误配置的中间缓存层或者不安全的服务器端查询构建都会导致难以发现的 bug。


强大的安全性来自可靠的设计模式和易于阅读的代码,而且,最常见的缺陷仍来自不恰当的业务逻辑设计和授权控制。


此外,我们推荐阅读Shopify’s GraphQL design tutorial,它分享了他们的经验教训以及如何利用第三方库进行安全配置和授权,从而让社区能共同受益。


原文链接:


https://labs.bishopfox.com/tech-blog/design-considerations-for-secure-graphql-apis


2020-10-22 15:043882
用户头像

发布了 165 篇内容, 共 71.2 次阅读, 收获喜欢 342 次。

关注

评论

发布
暂无评论
发现更多内容

华为云12·12直播EI专场即将开始,满足电商行业全场景搜索需求

科技怪授

华为云

关于K8s集群环境工作组隔离配置多集群切换的一些笔记

山河已无恙

k8s管理 K8s 多集群管理 12月月更

架构实战模块1作业

Geek_e3a35c

场景 | 大型电商企业运营管理数字化解决方案

九科Ninetech

Sovit3D引擎快速构建智慧变电站三维可视化系统

2D3D前端可视化开发

物联网 智慧变电站 智能变电站 数字孪生变电站 变电站可视化

AngularJS进阶(四十)创建模块、服务

No Silver Bullet

服务 模块 AngularJS 12月月更

AngularJS进阶(四十一)AngularJS中使用Chart.js制折线图与饼图实例

No Silver Bullet

AngularJS 12月月更 Chart.js 折线图与饼图

几种数据库jar包获取方式

华为云开发者联盟

数据库 华为云 12 月 PK 榜 jar包

什么样的web前端培训靠谱?

小谷哥

直播继续!华为云Solution as Code一键高效上云,解决方案开箱即用

科技怪授

华为云

大数据培训出来就业前景如何

小谷哥

打造算力新引擎!安擎上海智能制造基地正式运营

科技热闻

震惊,WSL2居然可以挂载USB

DisonTangor

WSL2 usb

AngularJS进阶(三十九)基于项目实战解析ng启动加载过程

No Silver Bullet

项目实战 AngularJS 12月月更 启动加载

云原生 AI 的资源调度和 AI 工作流引擎设计分享

Baidu AICLOUD

AI工程化 异构计算 云原生AI 百度百舸

【计算讲谈社】第十五讲|云端即时渲染:下一代互联网的算力基座?

大咖说

数字人 云游戏

声网管浩森:元宇宙派对场景的最佳实践

声网

实践 元宇宙 RTE2022

横空出世!阿里巴巴Spring全家桶实战笔记真香

Java永远的神

spring 源码 架构师 springboot SpringCloud

浪潮 KaiwuDB 陈磊:布局数字能源,创新助力 “双碳”

KaiwuDB

Verilog的语句块

攻城狮Wayne

Verilog Verilog语法 Verilog语句块

下一个AI舞台,名叫煤矿

脑极体

AlibabaP8,耗时182天肝出来1015页分布式全栈手册

程序知音

Java 分布式 后端 java架构

终于被我发现了这个推特视频下载的方法!超级简单!支持苹果安卓双系统!

frank

推特视频下载

java自学好还是培训好?

小谷哥

大数据培训工作就业前景怎么样

小谷哥

喜报 | Bonree ONE 2.0荣获信通院“2022IT新治理年度明星产品”

博睿数据

可观测性 博睿数据 荣誉 ONE平台

一文带你快速上手云日志服务

华为云PaaS服务小智

云计算 运维 日志管理

上海靠谱的前端培训机构有没有推荐

小谷哥

来聊一聊 ElasticSearch 最新版的 Java 客户端

江南一点雨

Java elasticsearch springboot ES

面了40+岁的大叔,没有录用,并不是因为年龄

产品运营心经

工作经历 面试‘ 职场发展 大龄求职

极客时间运维进阶训练营第八周作业

好吃不贵

怎样设计安全的GraphQL API?_安全_Jake Miller_InfoQ精选文章