GraphQL介绍
GraphQL概述
GraphQL 是一种查询语言,用于 API 设计和数据交互。它是由 Facebook 发布的一款新型的数据查询和操作语言,自 2012 年起在内部使用,自 2015 年起获得开源许可。由于技术原因,越来越多的公司使用 GraphQL 并将其后端切换到这个新系统,但是,虽然这种查询语言有很多优点,但随着查询变得更加复杂,它也有一些安全问题。信息泄露、业务逻辑错误、IDOR 和不当访问控制是 GraphQL 端点上最常见的漏洞。
GraphQL与传统RESTful API的区别
GraphQL 允许客户端在一个请求中明确地指定需要的数据,并返回预期的结果,而不是像 RESTful API 那样只能获取预定义的资源。因此,GraphQL 简化了客户端与服务器之间的通信,提高了应用程序的性能和可扩展性。
与传统的 RESTful API 不同,GraphQL 通过将数据查询和数据修改分离开来,使得客户端能够更灵活地控制所需数据的粒度和类型,并且在多个资源之间建立关系。这样,客户端就可以很容易地实现高效的数据获取和更新,而无需为每个特定的用例编写特定的 API。
GraphQL应用
目前正在使用GraphQL的大型公司包括Facebook、PayPal、GitHub、Shopify、Twitter、Tesla、Hackerone等大型公司,可见GraphQL正在迅猛发展。
GraphQL渗透测试前置知识
GraphQL查询语言
我们根据前文已经得知,GraphQL是一种用于API的查询语言,它支持很多种查询方式:
- Query
- Mutation
- Subscription
- Input
- Enum
- Union
- Interface
我们接下来主要介绍一下Query、Mutation、Subscription这三种。
Query
Query是GraphQL中最常用的一种方式。它用于从服务端获取数据,类似于RESTful API的GET方法。使用Query可以指定需要返回的字段以及过滤条件。
例如,以下查询会请求服务器返回用户ID为1的用户名和电子邮件地址:
query {
user(id: 1) {
name
email
}
}
Mutation
Mutation用于在服务端修改或添加数据,类似于RESTful API的POST、PUT和DELETE方法。Mutation支持向服务端提交一些参数,并根据参数来执行相应的操作。
例如,以下Mutation会将用户ID为1的用户名更改为”NewName”:
mutation {
updateUser(id: 1, name: "NewName") {
id
name
email
}
}
Subscription
Subscription是GraphQL中的一种高级特性,它允许客户端通过WebSocket连接实时接收来自服务器的数据更新。这对于需要实时通知的应用程序非常有用,如在线聊天、股票报价等。
例如,以下Subscription会订阅一个名为newMessage的频道,并在有新消息时返回消息内容:
subscription {
newMessage(channel: "chat") {
content
author
}
}
GraphQL渗透测试方法和流程
- 渗透测试准备工作
- 渗透测试步骤
- 枚举 GraphQL Schema
- 查询漏洞
- 注入漏洞
- 认证和授权漏洞
常见的GraphQL路径
/graphql
/graphql-console
/graphql-devtools
/graphql-explorer
/graphql-playground
/graphql-playground-html
/graphql.php
/graphql/console
/graphql/graphql
/graphql/graphql-playground
/graphql/schema.json
/graphql/schema.xml
/graphql/schema.yaml
/graphql/v1
/HyperGraphQL
/je/graphql
/laravel-graphql-playground
/lol/graphql
/portal-graphql
/v1/api/graphql
/v1/graphql
/v1/graphql-explorer
/v1/graphql.php
/v1/graphql/console
/v1/graphql/schema.json
/v1/graphql/schema.xml
/v1/graphql/schema.yaml
/v2/api/graphql
/v2/graphql
/v2/graphql-explorer
/v2/graphql.php
/graph
/graphql/console/
/graphiql
/graphiql.php
内省攻击
内省攻击本质上来说就是因为没有修改默认配置导致攻击者可以通过查询 __schema
或者 __type
等系统级别的 Schema 来获取服务器上定义的所有类型、字段、枚举等信息。攻击者可以利用这些信息去了解服务器的数据结构和业务逻辑,为下一步的攻击行动做准备。
内省攻击包含以下几个方面:
- 获取所有暴露的接口和类型信息:攻击者可以使用
__schema
查询来获取所有可用的 Schema 信息,包括对象类型、标量类型、枚举类型、接口类型和输入类型等。 - 获取所有字段信息:攻击者可以通过
__type.fields
查询来获取所有字段信息,包括字段名称、类型和描述等。 - 获取实际数据:攻击者可以通过查询实际数据,如用户账号、密码、秘密答案等,从而获取更高的权限或者直接篡改系统。
如下三段GraphQL 查询语句本质上是相同的,都是用于获取 GraphQL Schema 的元数据信息。它们的区别在于格式和编写方式
{__schema{queryType{name}mutationType{name}subscriptionType{name}types{...FullType}directives{name description locations args{...InputValue}}}}fragment FullType on __Type{kind name description fields(includeDeprecated:true){name description args{...InputValue}type{...TypeRef}isDeprecated deprecationReason}inputFields{...InputValue}interfaces{...TypeRef}enumValues(includeDeprecated:true){name description isDeprecated deprecationReason}possibleTypes{...TypeRef}}fragment InputValue on __InputValue{name description type{...TypeRef}defaultValue}fragment TypeRef on __Type{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name}}}}}}}}
{"query": "query IntrospectionQuery{__schema{queryType{name}mutationType{name}subscriptionType{name}types{...FullType}directives{name description locations args{...InputValue}}}}fragment FullType on __Type{kind name description fields(includeDeprecated:true){name description args{...InputValue}type{...TypeRef}isDeprecated deprecationReason}inputFields{...InputValue}interfaces{...TypeRef}enumValues(includeDeprecated:true){name description isDeprecated deprecationReason}possibleTypes{...TypeRef}}fragment InputValue on __InputValue{name description type{...TypeRef}defaultValue}fragment TypeRef on __Type{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name}}}}}}}}"}
{"query":"query Query {n __schema {n queryType { name }n mutationType { name }n subscriptionType { name }n types {n ...FullTypen }n directives {n namen descriptionn locationsn args {n ...InputValuen }n }n }n }nn fragment FullType on __Type {n kindn namen descriptionn fields(includeDeprecated: true) {n namen descriptionn args {n ...InputValuen }n type {n ...TypeRefn }n isDeprecatedn deprecationReasonn }n inputFields {n ...InputValuen }n interfaces {n ...TypeRefn }n enumValues(includeDeprecated: true) {n namen descriptionn isDeprecatedn deprecationReasonn }n possibleTypes {n ...TypeRefn }n }nn fragment InputValue on __InputValue {n namen descriptionn type { ...TypeRef }n defaultValuen }nn fragment TypeRef on __Type {n kindn namen ofType {n kindn namen ofType {n kindn namen ofType {n kindn namen ofType {n kindn namen ofType {n kindn namen ofType {n kindn namen ofType {n kindn namen }n }n }n }n }n }n }n }"}
可以使用burp的插件进行分析
之后就可以查找其中一些漏洞了,比如修改ID参数查询其他人员信息
如果graphql内省模式被禁用,可以尝试使用工具。
https://github.com/nikitastupin/clairvoyance
https://github.com/assetnote/batchql
GraphQL 渗透测试实战案例分析
消耗服务器资源攻击案例
我们首先请求一次该接口发现用时30481
然后添加一个systemUpdate参数再次请求,可以看到时间变成了80725。如果添加更多的systemUpdate参数即可导致攻击发生。
SSRF漏洞案例
防御和修复 GraphQL 漏洞的建议
- 限制查询语句的深度和复杂度:GraphQL 支持嵌套查询和参数化查询,这使得攻击者可以构造非常复杂的查询来增加服务器的负载,甚至可能导致拒绝服务攻击。为了防范此类攻击,可以对查询语句进行深度和复杂度限制,以确保每个查询不会占用过多的资源。
- 限制查询的访问权限:GraphQL API 应该只允许授权访问,而不是任何人都可以访问。可以通过身份验证、IP 白名单、API 密钥等方式来限制查询的访问权限,从而避免恶意查询和攻击。
- 限制查询返回的字段和数据量:攻击者可以利用查询返回大量的数据来耗尽服务器资源或者获取敏感信息。为了防止这种情况发生,应该限制每个查询返回的字段和数据量,并对某些敏感字段进行隐藏或者过滤处理。
- 检查输入参数的合法性:GraphQL 允许客户端自由传递参数,这也使得攻击者可以利用参数注入漏洞来攻击系统。因此,在服务器端需要对输入参数进行严格校验和过滤,避免恶意参数的注入和攻击。
- 关闭内省查询:GraphQL 内省机制被用来获取服务器上定义的所有类型、字段、枚举等信息。攻击者可以利用这些信息了解服务器的数据结构和业务逻辑,从而进行进一步攻击。为了防范此类攻击,应该关闭或限制内省查询功能。
参考
https://blog.yeswehack.com/yeswerhackers/how-exploit-graphql-endpoint-bug-bounty/
https://zhuanlan.zhihu.com/p/390876937
注:技巧,可以了解 GraphQL 模式的功能。{“query”:”query {n systemn}”,”variables”:null}
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.e1idc.net