0x00 Introduction
GraphQL is an API query language developed by Facebook, aiming to improve communication efficiency between the client and the server. At certain times, REST API needs to be called multiple times to return the required resources, while GraphQL allows the client to explicitly specify the data it needs, which can be used for precise data queries. GraphQL official documentation:https://graphql.org/, Chinese document:https://graphql.cn/.
Here is a simple example,query
indicating the query operation,{}
indicating the selection set,Book
indicating the object to be queried,id: "1"
indicating the query with the specified parameter id of 1,name
andauthor
indicating the fields to be queried.

query {
Book(id: "1") {
name
author
}
}
To better learn and understand GraphQL Attack later, it is necessary to learn several related concepts of GraphQL, here we go.
1. Schema
Schema (pattern) in GraphQL is a definition of a data model, describing the data structure that the client can access and operate on. It is like a database schema diagram or API documentation, specifying the data types that can be queried (query) and modified (mutation) and their relationships. A Schema mainly includes three operation types, namely:query
,mutation
andsubscription
.
This is a bit abstract, let's take a specific example, as follows: defined a namedBook
The object type, which has 4 fields, respectivelyid
,title
,author
,year
. It can be simply compared to a Book class, but this class only has properties without methods.Note: These types are defined on the server using SDL (Schema Definition Language).
type Book {
id: ID!
title: String!
author: String!
year: Int
}
is definedBook
After defining the type, aQuery
Type (The query type is mandatory in each Schema, see:https://spec.graphql.org/draft/#sec-Root-Operation-Types)。
type Query {
# Query all books, returning an array containing all books
books: [Book!]!
# Query a single book by book ID
bookById(id: ID!): Book
# Query books by author, returning all books by the specified author
booksByAuthor(author: String!): [Book]!
# Query books published before a specified year
booksBeforeYear(year: Int!): [Book!]!
}
If you want to modify a piece of data, you also need to defineMutation
type (optional, if you need to modify the data, you must define the type).
type Mutation {
# Add a new book
addBook(id: ID!, title: String!, author: String!, year: Int): Book!
# Update book information
updateBook(id: ID!, title: String!, author: String!, year: Int): Book!
# Delete a book
deleteBook(id: ID!): Boolean!
}
In addition, there is also aSubscription
types can be defined according to business requirements (optional).
type Subscription {
# Subscribe to the book addition event
bookAdded: Book!
# Subscribe to the book deletion event
bookDeleted: ID!
}
Alright, let's define the above-mentionedBook
,Query
,Mutation
,Subscription
Four object types combined together constitute a complete GraphQL Schema.
2. Type
The abstract data model (Schema) of GraphQL is described by Type, each Type consists of several Fields (fields), and each Field points to a certain Type. Types can be divided into:Scalar
,Object
,Interface
,Union
,Enum
,Input
these types, the focus is onScalar Type
(scalar type)andObject Type
(object type).
Scalar Type
including:String
,Int
,Float
,Boolean
,Enum
,ID
, such as the following code inID!
,String!
,Int
are scalar types (followed by!
notation, indicating that the field cannot be empty), in addition, new scalars (not the focus) can also be declared.Object Type
It can be used to express some complex data types, such as the following code inBook
This is an object type, which includes 4 Fields (fields), each pointing to a certain Type.
type Book {
id: ID!
title: String!
author: String!
year: Int
}
The type of a field generally uses scalar types, but can also be another object type.
type User {
id: ID
name: String
}
type Book {
id: ID!
title: String!
author: User
}
3. Operations
The GraphQL specification mainly includes three operation types, namely: Query (used to query data from the server), Mutation (used to operate data on the server, including: add, modify, delete, etc.), and Subscription, which are also known asroot operation type
, known as the root operation type.
In simple terms, it is defined as follows:Book
type, but this type cannot be accessed and operated directly, and needs to be implemented through the three root operation types Query, Mutation, Subscription in the specification, and these three root operation types need to be explicitly defined and cannot be used directly.Note: In the Schema, besides Query which is required, the other two are optional.
3.1 Query
define the root query type, you can customize the naming as needed (the default isQuery
),after custom naming, it is necessary toschema
defined to identify. Can only be identified according toQuery
format defined to query.
# The schema definition is used to specify the entry for the three operation types Query, Mutation, Subscription
# If using the default naming (Query, Mutation, Subscription), the schema definition can be omitted
schema {
query: RootQueryType
mutation: RootMutation
}
type RootQueryType {
books: [Book!]!
# Query books by ID
bookById(id: ID!): Book
}
type Book {
id: ID!
title: String!
author: String!
year: Int
}
type RootMutation {
# Add a book
addBook(title: String!, author: String!, year: Int): Book!
# Update book information
updateBook(id: ID!, title: String, author: String, year: Int): Book!
# Delete a book
deleteBook(id: ID!): Boolean!
}
type Subscription {
# Subscribe to the book addition event
bookAdded: Book!
# Subscribe to the book deletion event
bookDeleted: ID!
}
GraphQL Query is similar to RESTful API's GET request, mainly used to obtain specified data from the server. The above is the GraphQL Schema defined by the server, and the following is the query request initiated by the client. The following three query methods are all general.
# Query all books
query {
books{
id
title
author
year
}
}
# Query by ID
query {
bookById(id: "1") {
id, title, author, year
}
}
# Query books by author
query {
booksByAuthor(author: "JJ1ng") {
id title year
}
}
# Query books by specified year
query {
booksBeforeYear(year: 2025) {
id
title
author
}
}
The keyword can be omitted when performing Query query operations, but it cannot be omitted for Mutation and Subscription operations.
query {
bookById(id: "1") {
id
title
author
year
}
}
# The above can be changed to the following form
{
bookById(id: "1") {
id
title
author
year
}
}
And you can also customize the name of the query (known as the operation name), which can be written or not. As shown in the followinggetBookById
.
query getBookById {
bookById(id: "1") {
id
title
author
year
}
}
3.2 Mutation
GraphQL Mutation is mainly used for editing, modifying, and deleting operations. Mutation can also use types, names, structures, and other content to specify the data to be modified. If a Mutation operation type is defined in the Schema, predefined modifications can be made to the data on the server.
mutation {
addBook(title: "1984", author: "George Orwell", year: 1949) {
id
title
author
year
}
}
3.3 Subscription
GraphQL Subscription is used for real-time data updates. Clients can subscribe to certain events, and when the server-side data changes, the server will actively push updates to the client. It is mainly used in real-time interaction scenarios.
subscription {
bookAdded {
id
title
author
}
}
4. Introspection
Introspection is an inherent feature of GraphQL, used to query information about the Schema that has been defined on the server. In the introspection system, many metadata types are also built-in, including:__schema
,__type
,__typeKind
,__field
,__inputValue
,__enumValue
,__directive
. For a complete structure and the specific meaning of each field, refer to the documentation:https://spec.graphql.org/draft/#sec-Schema-IntrospectionHere are several common metadata type prototypes introduced as follows.
type __Schema {
description: String
types: [__Type!]!
queryType: __Type!
mutationType: __Type
subscriptionType: __Type
directives: [__Directive!]!
}
type __Type {
kind: __TypeKind!
name: String
description: String
fields(includeDeprecated: Boolean = false): [__Field!]
interfaces: [__Type!]
possibleTypes: [__Type!]
enumValues(includeDeprecated: Boolean = false): [__EnumValue!]
inputFields(includeDeprecated: Boolean = false): [__InputValue!]
ofType: __Type
specifiedByURL: String
}
type __Field {
name: String!
description: String
args(includeDeprecated: Boolean = false): [__InputValue!]!
type: __Type!
isDeprecated: Boolean!
deprecationReason: String
}
in}}__schema
In the structurequeryTye
is used to represent the query type of the GraphQL service, and the object type is__Type
, and__Type
field in the typename
, which is used to record the entry of the query type and also includes afields
field, which is a collection that records the query fields supported by the query type. The following request is used to query the query type name of the GraphQL service (if not modified, it is the defaultQuery
), as well as all of its fields and the types of the fields.
{
__schema {
queryType {
name
fields {
name
type {
name
}
}
}
}
}
Similar to this ismutationType
andsubscriptionType
object.
{__schema{mutationType{name, fields{name type{name}}}}}
{__schema{subscriptionType{name, fields{name type{name}}}}}
in}}__schema
In the structure, there is alsotypes
The field is a collection that records all types in the Schema (including: object types, scalar types, and metadata types).
{
__schema {
types {
name
}
}
}
in}}__schema
structure oftypes
field, the type of__Type
, and__Type
The type also contains afields
field infields
There is aname
Field, which is used to record the name of the field, that is, through the following query, you can obtain all types of GraphQL services and the fields contained in these types.
{
__schema {
types {
name
fields {
name
}
}
}
}
Query all fields of a specified type.
{
__type(name:\"user\"){
fields{
name
}
}
}
0x01 Vulnerability
GraphQL testing tools:
- https://github.com/Escape-Technologies/goctopus
- https://github.com/swisskyrepo/GraphQLmap
- https://github.com/doyensec/GQLSpection
- https://github.com/dolevf/graphw00f
1. Detection
GraphQL defines how to handle queries through types and names, rather than through endpoints and HTTP request methods like RESTful API. That is, all GraphQL operations use the same endpoint (which can be understood as the same URL, usually with the POST request method). Common endpoint dictionary:https://github.com/danielmiessler/SecLists/blob/fe2aa9e7b04b98d94432320d09b5987f39a17de8/Discovery/Web-Content/graphql.txt.
After finding the GraphQL endpoint, a simple test can be performed to detect whether the target is using the GraphQL service, the request type isapplication/json
If the correct echo is not received, different request methods and types can be tried.
{"query": "{}"}
{"query": "{__schema}"}
{"query": "{__typename}"}
{"query": "{__schema{types{name}}}"}
{"query": "{__schema{queryType{name}}}"}
{"query": "{__schema{types{name,fields{name}}}}"}
The response as follows indicates a GraphQL service. Metadata field__typename
Used to return the type of the current object, existing in any GraphQL service.
2. Info Gathering
Since it is impossible to know the supported query types and field names of the target GraphQL Schema in the real environment, this information can be obtained through introspection queries (similar to the Swagger API documentation). In addition, introspection queries may also leak some sensitive information, so remember to disable introspection queries in the real environment.
{"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 ofType{kind name}}}}}}}}"}
query {__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}}}}}}}}
You can also perform introspection queries directly through the built-in functionality of BurpSuite.
If the target disables introspection queries, you can use the Clairvoyance tool for automated collection of API information.
# Installation
pip install clairvoyance
# Use
clairvoyance https://xxx.com/graphql -o schema.json
In addition, you can also obtain information about the target through brute force, refer to the following section 'Information Disclousure'. Dictionary:https://github.com/Escape-Technologies/graphql-wordlist.
3. Visualizing
The result of the introspection query is often very long and difficult to handle, you can use graphql-voyager to visualize the association between Schema entities. It can be realized through an online website, the address is:https://graphql-kit.com/graphql-voyager/Copy the result of the introspection query to the arrow position.
4. DVGA
DVGA (Damn Vulnerable GraphQL Application, an easily attacked GraphQL application) is a GraphQL target environment that can be used for learning and exercising GraphQL security-related skills, the target site is:https://github.com/dolevf/Damn-Vulnerable-GraphQL-Application.
GraphQL is just a kind of API query technology, which will also have common vulnerabilities, such as: SQL injection may exist when involving databases, SSRF may exist when involving remote loading, and JWT-related vulnerabilities may exist when involving JWT, so when encountering GraphQL, in addition to its unique vulnerabilities, we can also carry out targeted testing of other vulnerabilities according to the actual situation.
The installation steps are as follows, after execution, you can access port 5013.
git clone https://github.com/dolevf/Damn-Vulnerable-GraphQL-Application.git && cdDamn-Vulnerable-GraphQL-Application
docker build -t dvga .
docker run -d -t -p 5013:5013 -e WEB_HOST=0.0.0.0 --name dvga dvga
4.1 Information Disclosure
Click 'Private Pastes' to capture GraphQL requests.
4.1.1 Introspection
Firstly, use 'introspection query' and visualization tools to view the associations between GraphQL entities.
4.1.2 GraphiQL
GraphiQL (GraphQL Interface) is a test page of an integrated development environment, which can be used to construct queries and view results in real-time, and it will provide descriptive information about the GraphQL API, which may lead to information leakage. Common paths include:
/graphiql
/playground
/v1/graphql
/v2/graphql
/console
It may also leak related debugging information.
4.1.3 Suggestions
Useful information can be mined from the hints returned by the server. You can collect related dictionaries and, without introspection queries, you can enumerate to mine information about the target.
4.2 Denial of Service
The GraphQL API is vulnerable to DoS attacks because GraphQL supports various features, such as batch queries, which allow GraphQL requests to include multiple queries. Without limits, this can lead to a DoS attack.
4.2.1 Batch Query Attack
4.2.2 Deep Recursion Query Attack
From the visual legend of the introspection query, it can be seen that the object PastesObject references OwnerObject, and in the object OwnerObject, it also references PastesObject. Such an infinite nesting query can lead to a DoS attack.
4.2.3 Resource Intensive Query Attack
If system updates can be performed without authorization and the system update will make the website unusable, it can lead to a DoS attack.
4.2.4 Field Duplication Attack
A large number of duplicate fields.
4.2.5 Aliases based Attack
GraphQL queries do not support multiple identical properties, but they can be implemented through aliases, which can also lead to a DoS attack.
4.2.6 Directives Overloading
When a query request contains a large number of directives, it can lead to a DoS attack.
4.2.7 Pagination Limit Bypass
Pagination limit bypass is an attack type where the attacker tries to bypass the pagination control settings limit in the server-side GraphQL implementation. This attack occurs when the attacker manipulates the pagination parameters in the GraphQL query to bypass the expected page limit and retrieve more data than the server expects. For more details, please refer to:https://www.imperva.com/blog/graphql-vulnerabilities-common-attacks/.
4.3 SSRF
SSRF attacks can be attempted at any location where there is remote loading.
4.4 Code Execution
4.5 Injection
4.5.1 XSS
When the submitted data is not cleaned, it will also lead to XSS attacks.
4.5.2 Log Spoofing&Log Injection
For GraphQL's query and mutation operations, an operation name can be assigned, which is to note the approximate content of the request and facilitate debugging. As follows, give a query request aGetUser
the operation name, which can easily show that the request content is to obtain user information.
query GetUser {
User {
id
name
pass
}
}
However, since the operation name is customizable, the attacker can mislead the administrators by modifying the operation name to avoid detection. For example, the following is a change operation, but the operation name isGetUser
This can mislead the administrators to some extent.
mutation GetUser {
updateUser(name:"admin", pass:"123456") {
id
name
pass
}
}
4.5.3 SQLi
There is a risk of SQL injection at any place where there is database interaction, and GraphQL API is no exception.
4.5 Authorization Bypass
4.6.1 JWT Token Forge
First go throughcreateUser
interface.
Then create a new user throughlogin
interface to return the JWT.
and change the identity in the JWT to admin.
Finally, use a forged JWT to go through the interfaceme
Obtain the administrator's password.
4.6.2 Interface Protection Bypass
Querying on the test page is denied.
can be modifiedCookie
Forenable
to bypass.
4.6.3 Query Deny List Bypass
Creating a GraphQL API whitelist and blacklist is a common method to prevent malicious queries from accessing the API. However, it is easy to bypass the blacklist. As can be seensystemHealth
It is not allowed to be accessed and exists on the blacklist.
By adding the operation name, it is possible to bypass the restrictions of the blacklist.
4.7 Miscellaneous
4.7.1 Query Weak Password Protection
Due to the feature of GraphQL supporting aliases, multiple queries can be performed in one request, so if the website has restrictions on enumerations, it can try to use aliases for brute-force attacks.
4.7.2 Arbitrary File Write // Path Traversal
0x02 PortSwigger
The general approach is to obtain data similar to API documentation through 'introspection query', and construct related queries to obtain target sensitive information based on these data. Lab address:https://portswigger.net/web-security/all-labs#graphql-api-vulnerabilities
1. Accessing private GraphQL posts
First step, obtain information about the target GraphQL through 'introspection query'.
Second step, visualize the query results through online websites. Website address:https://graphql-kit.com/graphql-voyager/.
The final step is to construct requests to obtain sensitive information. It can be easily modified on the 'GraphQL' panel.
2. Accidental exposure of private GraphQL fields
Use 'introspection query' to obtain information about the target GraphQL and visualize the associations between entities through online websites.
Construct requests to obtain sensitive information.
3. Bypassing GraphQL introspection defenses
To prevent attacks, developers often filter__schema
These characters are used to prevent 'introspection query'. As an attacker, you can try the following methods to bypass.
- Add some special characters, such as: spaces, line breaks, comments, etc.
- Change the request method to POST
- Change the request type to
x-www-form-urlencoded
Firstly, find the GraphQL Endpoint.
An error message indicating that introspection query is not allowed is prompted during the scan.
The__schema
and{
Line breaks can bypass detection.
The result of introspection query is saved to a JSON formatted file, then import the Inql plugin, which can construct corresponding operations based on the result of introspection query. Download address of Inql plugin:https://github.com/doyensec/inql.
The result of introspection query can tell usDeleteOrganizationUserInput
Type an Int parameter called id.
4. Bypassing GraphQL brute force protections
GraphQL queries do not support multiple identical properties, such as the following query is aIncorrect example.
query getProductDetails {
getProduct(id: 1) {
id
name
}
getProduct(id: 2) {
id
name
}
}
If you want to implement the above requirements, you can use Aliases (aliases) to achieve this.
query getProductDetails {
product1: getProduct(id: 1) {
id
name
}
product2: getProduct(id: 2) {
id
name
}
}
The returned results are roughly in the following form:
{
"data": {
"product1": {
"id": 1,
"name": "Juice Extractor"
},
"product2": {
"id": 2,
"name": "Fruit Overlays"
}
}
}
Many websites have various anti-brute force measures, some of which limit the number of HTTP requests rather than the number of operations in a single request. In GraphQL, the 'alias' can send multiple query requests in a single request, which can effectively bypass the brute force measures.
When performing password brute force attacks, the error prompts are too many, and the account is banned for one minute.
to conduct brute force attacks based on 'alias'.
5. Performing CSRF exploits over GraphQL
for requests whose type isapplication/json
ofPOST
requests cannot implement CSRF attacks, becauseapplication/json
type requests cannot be sent in the form of web forms. Even if JSON format requests are sent through JavaScript, they will be restricted by the same-origin policy. But if the GraphQL server does not verify the request type and there is no related CSRF protection, it may also lead to CSRF vulnerabilities.
after logging in, the data packet to modify the user's email is obtained.
because it isapplication/json
type packets cannot be used directly for CSRF attacks. But the GraphQL endpoint also supportsx-www-form-urlencoded
format.
0x03 Root-Me
Target field address:https://www.root-me.org/en/challenge/network-server/?titre_co=graphql
1. Introspection
Obtain target information through introspection queries and visualize it through Graphql-vayager.
2. Injection
This level restricts direct interaction with the GraphQL endpoint.
Through conjecture, it may be the data submittedq=China
Concatenate it to the normal query request and then query by the server.
Successfully verify the previous conjecture by constructing Payload.
Query all types and fields of the Schema.
3. Mutation
Directly querying 'flag' prompts that there is no permission.
After the Mutation operation is executed, the execution result will be returned, which means that Mutation can also achieve the function of querying, but the content of the query is the content after the Mutation operation. As shown below, you can see that the result of the Mutation operation is returned after the execution of the Mutation operation.
The results of introspection queries indicate that the 'flag' field is in the Nude object, and the Nude object can be controlled through nudeId. Although there is no permission to query the content of the Nude object, the content of the flag can be leaked based on the characteristic that the result of the Mutation operation will be returned.
0x04 Reference
https://www.freebuf.com/articles/377142.html
https://www.cnblogs.com/zhibing/p/17350053.html
https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/GraphQL%20Injection
https://medium.com/search?q=Hacking+GraphQL+for+Fun+and+Profit
https://www.imperva.com/blog/graphql-vulnerabilities-common-attacks/
https://cheatsheetseries.owasp.org/cheatsheets/GraphQL_Cheat_Sheet.html

评论已关闭