GraphQL安全概览与测试技巧

本文深入探讨GraphQL技术的安全风险,提供实用的测试技巧,包括端点发现、权限绕过、SQL注入和DoS攻击防护,帮助开发者和安全人员构建更安全的GraphQL应用。

GraphQL - 安全概览与测试技巧

2018年5月17日 - 作者:Paolo Stagno

随着GraphQL技术的日益普及,我们总结了有关常见安全错误的文档和技巧。

什么是GraphQL?

GraphQL是Facebook开发的一种数据查询语言,于2015年公开发布。它是REST API的替代方案。 即使您没有看到任何GraphQL,您可能已经在使用它,因为它运行在Facebook、GitHub、Pinterest、Twitter、HackerOne等许多大型科技公司上。

关于这项技术的几个关键点:

  • GraphQL提供了API中数据的完整且可理解的描述,并赋予客户端精确请求所需数据的能力。查询总是返回可预测的结果。
  • 典型的REST API需要从多个URL加载,而GraphQL API在单个请求中获取应用程序所需的所有数据。
  • GraphQL API按类型和字段组织,而不是端点。您可以从单个端点访问所有数据的全部功能。
  • GraphQL是强类型的,确保应用程序只请求可能的内容,并提供清晰有用的错误信息。
  • 可以向GraphQL API添加新字段和类型,而不会影响现有查询。老化的字段可以被弃用并从工具中隐藏。

在我们开始深入探讨GraphQL安全领域之前,这里简要回顾一下它的工作原理。官方文档写得很好,非常有帮助。

一个GraphQL查询如下所示:

基本GraphQL查询

1
2
3
4
5
6
7
8
query{
	user{
		id
		email
		firstName
		lastName
	}
}

而响应是JSON:

基本GraphQL响应

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
	"data": {
		"user": {
			"id": "1",
			"email": "paolo@doyensec.com",
			"firstName": "Paolo",
			"lastName": "Stagno"
		}
	}
}

安全测试技巧

由于Burp Suite不太理解GraphQL语法,我建议使用graphql-ide,这是一个基于Electron的应用程序,允许您编辑和发送请求到GraphQL端点;我还编写了一个小的Python脚本GraphQL_Introspection.py,用于枚举GraphQL端点(通过内省)以提取文档。该脚本对于检查GraphQL模式以查找信息泄漏、隐藏数据和不打算访问的字段非常有用。

该工具将生成类似以下的HTML报告:

内省用于向GraphQL模式询问有关它支持的查询、类型等信息。

作为渗透测试人员,我建议查找发送到"/graphql"或"/graphql.php"的请求,因为这些都是常见的GraphQL端点名称;您还应该搜索"/graphiql"、“graphql/console/"、在线GraphQL IDE以与后端交互,以及”/graphql.php?debug=1"(调试模式,带有额外的错误报告),因为它们可能被开发人员留下开放状态。

测试应用程序时,验证是否可以在没有通常的授权令牌头的情况下发出请求:

由于GraphQL框架没有提供任何保护数据的手段,开发人员负责实现访问控制,如文档所述:

“然而,对于生产代码库,将授权逻辑委托给业务逻辑层”。

事情可能会出错,因此验证没有适当身份验证和/或授权的用户是否可以从服务器请求整个底层数据库非常重要。

使用GraphQL构建应用程序时,开发人员必须将数据映射到他们选择的数据库技术中的查询。这是可能容易引入安全漏洞的地方,导致访问控制破坏、不安全的直接对象引用甚至SQL/NoSQL注入。

作为一个破坏实现的示例,以下请求/响应表明我们可以获取平台上任何用户的数据(通过循环ID参数),同时转储密码哈希:

查询

1
2
3
4
5
6
7
8
9
query{
	user(id: 165274){
		id
		email
		firstName
		lastName
		password
	}
}

响应

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{
	"data": {
		"user": {
			"id": "165274",
			"email": "johndoe@mail.com",
			"firstName": "John",
			"lastName": "Doe"
			"password": "5F4DCC3B5AA765D61D8327DEB882CF99"
		}
	}
}

您必须检查的另一件事是在尝试执行非法查询时与信息泄漏相关:

信息泄漏

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
{
	"errors": [
		{
			"message": "Invalid ID.",
			"locations": [
				{
					"line": 2,
					"column": 12
				}
				"Stack": "Error: invalid ID\n at (/var/www/examples/04-bank/graphql.php)\n"
      			]
		}
	]
}

尽管GraphQL是强类型的,但SQL/NoSQL注入仍然是可能的,因为GraphQL只是客户端应用程序和数据库之间的一个层。问题可能存在于为从GraphQL查询中获取变量以查询数据库而开发的层中;未正确清理的变量导致老式的简单SQL注入。

对于Mongodb,NoSQL注入可能不那么简单,因为我们不能"玩弄"类型(例如,将字符串转换为数组。参见PHP MongoDB注入)。

GraphQL SQL注入

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
mutation search($filters Filters!){
	authors(filter: $filters)
	viewer{
		id
		email
		firstName
		lastName
	} 
}

{
	"filters":{
		"username":"paolo' or 1=1--"
		"minstories":0
	}
}

注意嵌套查询!它们可能允许恶意客户端通过过于复杂的查询执行DoS(拒绝服务)攻击,这些查询将消耗服务器的所有资源:

嵌套查询

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
query {
 stories{
  title
  body
  comments{
   comment
   author{
    comments{
     author{
      comments{
       comment
       author{
        comments{
         comment
         author{
          comments{
           comment
           author{
            name
           }
          }
         }
        }
       }
      }
     }
    }
   }
  }
 }
}

针对DoS的简单补救措施可以是设置超时、最大深度或查询复杂性阈值。

请记住,在PHP GraphQL实现中:

  • 默认情况下禁用复杂性分析
  • 默认情况下禁用查询深度限制
  • 默认情况下启用内省。这意味着任何人都可以通过发送包含元字段类型和模式的特殊查询来获取模式的完整描述

结语

GraphQL是一种有趣的新技术,可用于构建安全应用程序。由于开发人员负责实现访问控制,应用程序容易出现经典的Web应用程序漏洞,如访问控制破坏、不安全的直接对象引用、跨站脚本(XSS)和经典注入错误。与任何技术一样,基于GraphQL的应用程序可能容易出现开发实现错误,如这个真实示例:

“通过使用脚本,可以运行整个国家(我测试了美国、英国和加拿大)可能的数字组合通过这些URL,如果数字与Facebook帐户关联,则可以与名称和进一步详细信息(图像等)关联。”

@voidsec

资源:

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计