带有GraphQL的PentQL应用程序



最近,GraphQL越来越受欢迎,并且随着信息安全专家的兴趣日益增长。 该技术已被Facebook,Twitter,PayPal,Github等公司使用,这意味着现在该弄清楚如何测试这种API了。 在本文中,我们将讨论该查询语言的原理以及使用GraphQL测试应用程序渗透的方向。

为什么需要了解GraphQL? 该查询语言正在积极开发中,越来越多的公司正在为其实际使用。 在Bug Bounty程序的框架内,这种语言的流行度也在增长, 在这里这里这里都可以看到有趣的示例。

准备工作

一个测试站点 ,您将在本文中找到大多数示例。
您还可以用来学习的应用程序列表

要与各种API交互,最好使用GraphQL IDE:


我们建议使用最后一个IDE:Insomnia具有一个方便而简单的界面,其中有许多设置和请求字段的自动完成功能。

在直接继续使用GraphQL进行应用程序安全性分析的一般方法之前,我们回顾一下基本概念。

什么是GraphQL?


GraphQL是一种API查询语言,旨在为REST提供更有效,强大和灵活的替代方案。 它基于声明性数据采样,也就是说,客户端可以从API确切指定它需要什么数据。 GraphQL代替了多个API终结点(REST),提供了一个向客户端提供所请求数据的终结点。

REST和GraphQL之间的主要区别


通常,在REST API中,您需要从不同的端点获取信息。 在GraphQL中,要获取相同的数据,您需要进行一次查询以指示要接收的数据。



REST API提供了开发人员将放入API的信息,也就是说,如果您需要获得比API建议的更多或更少的信息,则需要采取其他措施。 同样,GraphQL准确提供了所请求的信息。
有用的补充是GraphQL具有描述客户端如何接收数据以及接收哪些数据的架构。

查询类型


GraphQL中有3种主要的查询类型:

  • 询问
  • 变异
  • 订阅方式

询问

查询查询用于检索/读取模式中的数据。

此类请求的示例:

query { allPersons { name } } 

在请求中,我们指示我们要获取所有用户的名称。 除了名称之外,我们还可以指定其他字段: ageidposts等。要找出我们可以获取的字段,您需要按Ctrl + Space。 在此示例中,我们传递参数,应用程序将使用该参数返回前两个记录:

 query { allPersons(first: 2) { name } } 

变异

如果需要查询类型来读取数据,则需要突变类型来写入,删除和修改GraphQL中的数据。

此类请求的示例:

 mutation { createPerson(name:"Bob", age: 37) { id name age } } 

在此请求中,我们创建了一个名称为Bob且年龄为37岁的用户(这些参数作为参数传递),在附件(花括号)中,指明了创建用户后要从服务器接收的数据。 为了了解请求是否成功以及获取服务器独立生成的数据(例如id) ,这是必需的。

订阅方式

GraphQL中的另一种查询类型是预订。 需要将系统中发生的任何更改通知用户。 它的工作方式如下:客户端订阅某个事件,然后与服务器建立连接(通常通过WebSocket),并且在发生此事件时,服务器向客户端发送有关已建立连接的通知。

一个例子:

 subscription { newPerson { name age id } } 

创建新的“人员”后,服务器将向客户端发送信息。 模式中订阅查询的存在比查询和变异少见。

值得注意的是,所有查询,变异和订阅功能都是由特定API的开发人员创建和配置的。

选配


实际上,为了清楚起见,开发人员经常在查询中使用别名和OperationName。

别名

用于查询的GraphQL提供了别名功能,该功能可以使您更容易理解客户端的要求。

假设我们有以下形式的查询:

 { Person(id: 123) { age } } 

它将显示ID为 123的用户名。让此用户名为Vasya。

这样,下次您就不会怀疑此请求将显示什么时,可以按以下方式进行操作:

 { Vasya: Person(id: 123) { age } } 

操作名称

除了别名,GraphQL还使用OperationName:

 query gettingAllPersons { allPersons { name age } } 

需要OperationName来确切解释请求的作用。

渗透测试


在弄清基础知识之后,我们直接进入渗透测试。 如何理解应用程序使用GraphQL? 这是具有GraphQL查询的示例查询:

 POST /simple/v1/cjp70ml3o9tpa0184rtqs8tmu/ HTTP/1.1 Host: api.graph.cool User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:65.0) Gecko/20100101 Firefox/65.0 Accept: */* Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate Referer: https://api.graph.cool/simple/v1/cjp70ml3o9tpa0184rtqs8tmu/ content-type: application/json Origin: https://api.graph.cool Content-Length: 139 Connection: close {"operationName":null,"variables":{},"query":"{\n __schema {\n mutationType {\n fields {\n name\n }\n }\n }\n}\n"} 

您可以通过一些参数了解这是GraphQL,而不是其他参数:

  • 在请求正文中有以下单词:__schema,字段,operationName,mutation等;
  • 在请求正文中,有许多字符“ \ n”。 如实践所示,可以将它们删除以使其更方便地阅读请求。
  • 通常将请求发送到服务器的方式:⁄graphql

很好,找到并确定。 但是,在何处插入引号如何找出需要使用的内容呢? 内省将解救。

内省


GraphQL提供了一种自省方案,即 描述我们可以获得的数据的方案。 因此,我们可以找出存在的请求,可以/应该将哪些参数传递给它们,等等。 请注意,在某些情况下,开发人员有意不允许对其应用程序进行自省。 但是,绝大多数仍然保留这种可能性。

考虑基本的查询示例。

例子1.获取各种请求

 query { __schema { types { name fields { name } } } } 

我们形成一个查询查询,表明我们要接收有关__schema的数据,并在其中输入类型,名称和字段。 在GraphQL中,有服务变量名称:__schema,__typename,__type。

在答案中,我们将接收方案中存在的所有类型的请求,它们的名称和字段。

例子2.获取特定请求类型的字段(查询,变异,描述)

 query { __schema { queryType { fields { name args { name } } } } } 

该请求的答案将是我们可以执行的用于接收数据的方案的所有可能请求(查询类型),以及它们可能/必要的参数。 对于某些查询,需要指定参数。 如果在不指定必需参数的情况下执行此类请求,则服务器应显示一条错误消息,您必须指定该错误消息。 代替queryType,我们可以替换mutationType和subscriptionType来分别获取所有可能的突变和预订请求。

示例3.获取有关特定请求类型的信息

 query { __type(name: "Person") { fields { name } } } 

由于此查询,我们获得了Person类型的所有字段。 作为参数,我们可以传递任何其他请求名称来代替Person。

现在我们可以弄清被测应用程序的一般结构,让我们确定我们要寻找的内容。

信息公开

大多数情况下,使用GraphQL的应用程序包含许多字段和查询类型,并且众所周知,应用程序越复杂和越大,配置和监视其安全性就越困难。 因此,通过仔细的自省,您可以找到一些有趣的东西,例如:用户的全名,他们的电话号码和其他关键数据。 因此,如果要查找类似的内容,则建议您检查应用程序的所有可能的字段和参数。 因此,作为其中一个应用程序的渗透测试的一部分,发现了用户数据:姓名,电话号码,出生日期,一些卡数据等。

一个例子:

 query { User(id: 1) { name birth phone email password } } 

通过id值,我们可以获得有关其他用户的信息(如果一切配置正确,则可能没有)。

注射剂

不用说,几乎在所有处理大量数据的地方,都有数据库吗? 在有数据库的地方-可能有SQL注入,NoSQL注入和其他类型的注入。

一个例子:

 mutation { createPerson(name:"Vasya'--+") { name } } 

这是查询参数中的基本SQL注入。

授权绕过
假设我们可以创建用户:

 mutation { createPerson(username:"Vasya", password: "Qwerty1") { } } 

假设服务器上的处理程序中有一个特定参数isAdmin,我们可以发送以下形式的请求:

 mutation { createPerson(username:"Vasya", password: "Qwerty1", isAdmin: True) { } } 

并让用户Vasya成为管理员。

多斯


除了所声明的便利之外,GraphQL还具有其自身的安全漏洞。

考虑一个例子:

 query { Person { posts { author { posts { author { posts { author ... } } } } } } } 

如您所见,我们创建了一个循环子查询。 有了大量这样的投资,例如5万,我们可以发送一个将由服务器处理很长时间的请求,或者将其完全“丢弃”。 服务器将不处理有效的请求,而是忙于打开虚拟请求的巨大嵌套。

除了大嵌套之外,查询本身也可能“繁重”-这是查询具有大量字段和内部附件的时候。 这样的请求还可能导致在服务器上进行处理的困难。

结论


因此,我们研究了使用GraphQL进行应用程序渗透测试的基本原理。 我们希望您学到了一些对自己有用的新东西。 如果您对此主题感兴趣,并且希望对其进行更深入的研究,我们建议您使用以下资源:


别忘了:实践使完美。 祝你好运

Source: https://habr.com/ru/post/zh-CN444708/


All Articles