Field Duplication in GraphQL API
Field Duplication in GraphQL API
Description
Field Duplication in GraphQL occurs when an attacker sends a query that requests the same field repeatedly, overloading the server's processing capabilities.
In GraphQL, clients can request multiple fields in a query, including the same field multiple times. However, excessive duplication of fields can result in a Denial of Service (DoS) attack by consuming server resources. This can degrade performance or cause a service outage. Example:
query overload {
user {
id
id
id
id
id
...
}
}
Security Impact of Field Duplication:
- Denial of Service: By duplicating the same field in a query, attackers can force the server to repeatedly process the same request, leading to excessive resource use and potential service crashes.
- Resource Exhaustion: Similar to Alias Overloading, this attack can cause spikes in CPU and memory usage, slowing down the system and affecting overall performance.
- Service Disruption: If not mitigated, Field Duplication attacks can make the GraphQL API unavailable to legitimate users, leading to system downtime or degraded service.
Recommendation
To mitigate the risk of Field Duplication attacks, you can take the following steps:
- Implement Query Complexity Limits: Enforce query complexity rules that consider duplicated fields as part of the overall cost of a query. This helps in limiting the number of duplicate fields processed, thus protecting the server from resource exhaustion.
- Limit Field Repetitions: Configure server-side limits on the number of times a field can be duplicated in a single GraphQL query. You can use tools like GraphQL Armor to enforce such limits and prevent field duplication overloading.
// Configuring for GraphQL Armor
GraphQLArmorConfig({
maxFieldDuplicates: {
// Enable or disable the plugin | default: true
enabled: true,
// Set the maximum number of field duplications allowed per query | default: 10
n: 10,
// Callbacks to execute when a query is accepted
onAccept: [],
// Callbacks to execute when a query is rejected
onReject: [],
// Propagate rejection details to the client | default: true
propagateOnRejection: true,
}
})
import graphql
from graphql.language import ast
from graphql.language import parser
from settings import api
def validate_field_duplicates(query: str) -> None:
"""
This validation prevents the execution of queries containing excessive
duplicated fields to avoid overloading the server.
"""
class FieldDuplicationParser(parser.Parser):
def parse_duplicates(self) -> list[ast.FieldNode]:
field_counts = {}
while self.peek(graphql.TokenKind.NAME):
field_name = self.parse_field().name.value
field_counts[field_name] = field_counts.get(field_name, 0) + 1
if field_counts[field_name] > api.API_MAX_FIELD_DUPLICATES:
raise graphql.GraphQLError("Exception - Max field duplicates exceeded")
return []
ast_parser = FieldDuplicationParser(query)
ast_parser.parse_document()
Links
Standards
- CWE_TOP_25:
- CWE_400
- PCI_STANDARDS:
- REQ_6_2
- REQ_6_4
- REQ_11_3
- OWASP_MASVS_L2:
- MSTG_PLATFORM_2
- OWASP_ASVS_L2:
- V4_1_3
- V4_1_5
- V5_3_3
- V5_3_4
- V9_1_1
- V9_1_2
- V12_1_1
- V12_1_2
- OWASP_ASVS_L3:
- V4_1_3
- V4_1_5
- V5_3_3
- V5_3_4
- V9_1_1
- V9_1_2
- V12_1_1
- V12_1_2
- V12_1_3
- SOC2_CONTROLS:
- CC_2_1
- CC_4_1
- CC_7_1
- CC_7_2
- CC_7_4
- CC_7_5
- CC_9_1