前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >渗透中遇到GraphQL怎么搞?

渗透中遇到GraphQL怎么搞?

作者头像
tnt阿信
发布2021-04-09 10:33:17
3.3K1
发布2021-04-09 10:33:17
举报
文章被收录于专栏:一个安全研究员

graphql使用

在我看来,graphql提供了一种api的解决方案。

以前我们查询api提供的数据是怎么做的呢?

举一个例子,例如现在有这么一个查询书籍信息的接口:/book/info,按照我们之前的解决方案,我们一般会传一个类似book_id的参数到这个接口,然后接口把书籍信息返回给我们

同样的,如果又有一个查询作者信息的需求,那么我们会新增一个接口:/author/info,并以book_id为参数查询作者信息

可以看到,以往我们使用的api查询数据的操作是分散的,彼此之间是没啥联系,查询多个数据就要向不同的接口发送多个请求

但是graphql很特别,它一般只提供一个接口/graphql,所有的数据查询操作都是向此接口发送请求,并且,只需要发送一次请求就可以获得多个数据

那graphql是怎么实现这一点的呢?

这得归功于graphql的面向对象思想

在graphql中,所有的数据形成了一张彼此相互关联的“图”,此处的“图”是指数据结构中的“图”

怕大家忘了啥是图,贴一张图回忆回忆

图论〔Graph Theory〕是数学的一个分支。它以图为研究对象。图论中的图是由若干给定的点及连接两点的线所构成的图形,这种图形通常用来描述某些事物之间的某种特定关系,用点代表事物,用连接两点的线表示相应两个事物间具有这种关系。图论是一种表示 "多对多" 的关系 图是由顶点和边组成的:(可以无边,但至少包含一个顶点)

图中的每一个顶点就是咱们的数据,那这些数据是怎么关联起来的呢?

实际上还是借助了面向对象的思想,graphql把每一种数据都给抽象成了一个类,例如咱们上面提到的两个接口,在graphql中,这两个接口背后对应的数据就可以被抽象为Book类以及Author类

但是,这里说的类只是一个概念,区别于咱们编程语言中的类,与其说它是一个类,不如说它是一个结构,在Graphql中,Book类可以这样描述

代码语言:javascript
复制
type Book {
    id: ID
    name: String
    pageCount: Int
    author: Author
}

Author类:

代码语言:javascript
复制
type Author {
    id: ID
    firstName: String
    lastName: String
    book: Book
}

其中Book类有一个属性是author,代表一本书的作者,而Author类中有一个属性是book,表示该作者写过的所有的书,这两个类一下子就产生了联系

如果用图论中的有向图表示这两个顶点,就是下面这个样子:

现在咱们只是对数据做了抽象描述,那么怎么把数据暴露给前端呢?咱们还需要借助一个类型

这个类型就是Query,在Query类中我们可以定义各个查询接口:

代码语言:javascript
复制
type Query {
    bookById(id: ID): Book
    authorById(id: ID): Author
}

上面就在Query类中定义了两个接口,bookById(id: ID): Book表示对外暴露的接口名为bookById,然后这个接口接受一个参数id,这个id的类型为ID,该接口的返回类型为Book

暴露了接口,我们前端就可以查询了,前端查询的格式也是很讲究的,例如我要查id为book-1的书籍的名字和页数,就可以传如下数据到接口/graphql:

代码语言:javascript
复制
{
    bookByID(id: "book-1"){
        name,
        pageCount
    }
}

如果我要查,id为book-1的书籍的名字以及其作者的名字,可以发送如下格式的数据:

代码语言:javascript
复制
{
    bookByID(id: "book-1"){
        name,
        author{
            firstName,
            lastName
        }
    }
}

返回结果也是很清晰的,如下:

总结起来,graphql的工作流程如下:

当然,这也只是一个整体上的流程,没有涉及到具体的代码实现,其实在写代码的时候还得考虑数据来自哪里,这就涉及到为每个数据类型配置dataFetcher了,具体的代码实现案例可以看官网的入门教程(java版),不再赘述:

https://www.graphql-java.com/tutorials/getting-started-with-spring-boot/#author-datafetcher

graphql安全风险

扯了这么多,那graphql都面临着哪些安全风险呢?

graphiql对外网开放,且无验证机制

graphiql实际上就是一个graphql的调试工具,有了该调试工具可以更方便我们执行graphql语句,但是对攻击者来说如果一个程序对外提供了/graphql接口,开没开graphiql接口也就没那么重要了

因为graphiql接口能做的,graphql接口也可以做到?

graphql内省机制

内省官方文档:https://graphql.cn/learn/introspection/

graphql内省机制涉及到的最大的问题就是信息泄露了,如果系统没有对内省机制进行处理,则可能会泄露系统中所有的可用的查询,以及查询支持的字段等等,也就是说整个系统处于裸奔状态

如果系统中有一些敏感查询,则会泄露很多信息,甚至影响正常的业务逻辑

graphql支持的内省查询有两个__schema、__type,其实使用__schema就够用了

查询graphql中注册的所有类型:

可以看到查询到了我们之前注册的Book以及Author类型,但是想要进一步利用,只是知道系统中注册的所有类型还不行,我们需要知道系统支持哪些查询,用如下语句:

可以看到,我们之前注册的两个查询也出来了,但是还不够,咱们还得知道这些查询下支持哪些字段以及是否需要参数:

可以看到成功查询出了bookById的查询的参数是id,返回类型是Book,然后我们在去看一下Book的字段就知道bookByID可以查询哪些字段了:

可以看到,Book下的字段有id,name,pageCount,author,那么我们就可以直接构造查询了:

上述过程就是一个完整的graphql内省机制的利用流程,我这里演示的接口就是单纯的查询信息,没啥危害,但是要知道真实环境中的graphql api可不只是用来做查询操作的,还有各种写操作,造成的危害也就上了一个层次

规避方案:目前还不了解graphql是否支持关闭内省机制,但是我们可以在业务上对内省机制进行限制,例如过滤查询中的__schema、__type关键词,这两个关键词都是小写,所以暂时也不需要担心大写绕过的问题(但是业务上对大小写进行了不正确的转换就另说了)

自动绑定

自动绑定原理其实很简单,和spring中的自动绑定机制有点类似,就是如果我爆破出了你的敏感接口、以及对应的字段,我就可以直接使用,这本就是graphql的一个特点,不算是漏洞,但是这确实会带来一些安全问题

规避方案:

  • 对敏感的graphql查询进行权限控制

ql注入

graphql实现了一套自己的查询语言,和spring中的el类似,graphql也是存在表达式注入的问题

漏洞原理:前端传入的参数未正确处理就直接拼接到了graphql语句中,例如下面这样的场景

代码语言:javascript
复制
String book_id = req.getParameter("book_id");
String gql_query = "{bookById(id:\""+book_id+"\"){name,pageCount}}";
用gql_query执行查询

现在如果我给book_id赋值为book-1"){name}authorById("author-1"){firstName}#

gql_query的值就变为:{bookById(id:"book-1"){name}authorById("author-1"){firstName}#"){name,pageCount}}

其中,#是注释符,经过拼接,查询的语义完全变了

当然,这样使用graphql的场景应该也不多,毕竟这已经违背了graphql的设计理念...

Dos攻击

其实我上面给的案例的那种写法就存在着Dos隐患,问题出在两个类型互相关联上,Book中有Author,Author中有Book,当数据量够大时,这样我们可以直接构造多层查询达到Dos效果

类似于xee攻击:https://www.cnblogs.com/lcamry/p/5737318.html

鉴权不严

鉴权问题是api通用的问题

只是开发者在使用graphql的过程中更容易忽略对敏感接口进行细粒度的鉴权,因为graphql是单路由的api,所以,开发者往往也只是对这个路由进行了权限判断

但是实际上graphql中注册的各个查询可能要求的权限是不一样的

例如只有admin权限才能调用的查询addMoney,就需要在业务上限制非admin用户不能访问

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-03-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 一个安全研究员 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • graphql使用
  • graphql安全风险
    • graphiql对外网开放,且无验证机制
      • graphql内省机制
        • 自动绑定
          • ql注入
            • Dos攻击
              • 鉴权不严
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档