What is it GraphQL ?
GraphQL
What is GraphQL?
GraphQL is a query language and runtime for APIs, developed by Facebook to solve problems developers faced with REST APIs. Instead of calling multiple endpoints to get related data, you send a single, structured request that returns just what you need — no more, no less.
Unlike REST, where the server defines the response structure, GraphQL gives control to the client. This makes it powerful, flexible, and highly customizable — but also introduces several security risks if not implemented carefully.
How GraphQL Works (Behind the Scenes)
When a client sends a GraphQL request, here’s what typically happens:
Parsing – The server parses the incoming query string.
Validation – It validates the query against the defined schema.
Execution – Resolvers are triggered for each field in the query.
Response – A structured JSON response is returned to the client.
GraphQL queries are usually sent via HTTP POST requests to a single endpoint, like /graphql
, with a body like:
1
2
3
{
"query": "query { user(id: 1) { name email } }"
}
The response is:
1
2
3
4
5
6
7
8
{
"data": {
"user": {
"name": "x0tiger",
"email": "x0tiger@example.com"
}
}
}
Core Components of GraphQL
Component | Description |
---|---|
Schema | Defines the types, fields, and operations allowed in the API. |
Query | For retrieving data (read operations). |
Mutation | For modifying data (create, update, delete). |
Subscription | For real-time updates using WebSockets. |
Resolver | The function behind each field that actually fetches the data. |
Example Schema:
1
2
3
4
5
6
7
8
9
type User {
id: ID!
name: String!
email: String!
}
type Query {
user(id: ID!): User
}
Real-World Usage of GraphQL
In large frontend applications (e.g. SPAs or mobile apps), GraphQL significantly improves performance and developer experience by:
Reducing the number of requests.
Preventing over-fetching or under-fetching data.
Allowing clients to evolve independently from the backend.
Example: A dashboard view on a mobile app might need only a few fields.
1
2
3
4
5
6
7
query {
currentUser {
name
profilePicture(size: SMALL)
unreadMessages
}
}
Features and Usage Patterns
Fragments
Used to avoid repeating field definitions.
1
2
3
4
5
fragment userFields on User {
id
name
email
}
Then used like:
1
2
3
4
5
query {
user(id: 5) {
...userFields
}
}
Aliases
Allow sending multiple queries with the same field name.
1
2
3
4
query {
firstUser: user(id: 1) { name }
secondUser: user(id: 2) { name }
}
Variables
Allow dynamic queries without rebuilding the query string.
1
2
3
4
{
"query": "query getUser($id: ID!) { user(id: $id) { name } }",
"variables": { "id": "1" }
}
Directives
Modify execution logic (e.g. conditionally including a field).
1
2
3
4
5
6
query getUser($showEmail: Boolean!) {
user(id: 1) {
name
email @include(if: $showEmail)
}
}
Security Risks in GraphQL APIs
Although GraphQL appears secure due to its strict schema and typed system, in practice many APIs expose dangerous behavior due to misconfiguration or weak controls.
Common Vulnerabilities
Risk | Description |
---|---|
Exposed Introspection | Allows full schema discovery (__schema , __type ). |
Broken Access Control | Lack of per-resolver permission checks. |
No Rate Limiting | Abuse via batching, aliases, deep nesting. |
Lack of Depth/Complexity Limits | Enables DoS via recursive queries. |
Injection Attacks | SQL/NoSQL injections inside query filters. |
CSRF with Cookies | When CORS is open and cookies are used for auth. |
Exposed Mutations | Unprotected create/update/delete operations. |
Excessive Error Disclosure | Leaks schema or stack traces. |
Attack Scenarios and Testing Techniques
Below are common GraphQL attack cases you can test against:
Introspection Enabled
Goal: Discover schema details
Payload:
1
{ __schema { types { name fields { name } } } }
Authorization Bypass
Goal: Access restricted fields
Payload:
1
query { adminPanel { secretToken } }
SQL Injection in Filters
Goal: Inject malicious query logic
Payload:
1
2
3
4
5
query {
users(where: { name: { _eq: "' OR 1=1 --" } }) {
id
}
}
Deep Recursion (Denial of Service)
Goal: Crash the server or spike CPU
Payload:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
query {
user(id: 1) {
posts {
comments {
user {
posts {
comments {
user {
name
}
}
}
}
}
}
}
}
Batch Queries (Mass Enumeration)
Goal: Enumerate data via batching
Payload:
1
2
3
4
5
query {
u1: user(id: 1) { email }
u2: user(id: 2) { email }
u3: user(id: 3) { email }
}
SSRF via Resolver
Goal: Fetch internal URLs via exposed resolver
Payload:
1
2
3
query {
fetchUrl(url: "http://localhost:8000/internal")
}
GraphQL Injection via Variables
Goal: Manipulate query structure indirectly
Payload:
1
2
3
4
5
6
{
"query": "query getUser($field: String!) { user { $field } }",
"variables": {
"field": "password"
}
}
Test Cases in GraphQL
Tools for Testing and Securing GraphQL
Tool | Description |
---|---|
GraphQLmap | CLI for automating attacks and fuzzing |
InQL | Burp Suite plugin for GraphQL testing |
Altair | GUI client for crafting queries |
GraphCrawler | Schema/path exploration & brute force |
GraphQL Voyager | Visualizes GraphQL schemas |
Recommendations for Securing GraphQL APIs
Disable introspection in production.
Limit query depth and total complexity.
Validate inputs strictly — don’t rely only on GraphQL types.
Enforce per-resolver authorization.
Log and monitor query patterns.
Throttle and rate-limit requests.
Block unused or dangerous mutations.
Summary
GraphQL is a flexible, efficient, and modern way to build APIs. However, its dynamic nature and client-driven queries introduce unique security challenges that differ from REST.
To secure GraphQL:
Know your schema.
Control access at the resolver level.
Limit what clients can do — not just what they can see.
And always test, monitor, and review.
When done right, GraphQL boosts productivity. When done wrong, it can expose your entire backend.