GraphQL-Sicherheit
GraphQL bietet eine mächtige Flexibilität, führt aber einzigartige Angriffsvektoren ein: Query-Complexity-Angriffe, Introspection-Missbrauch, Authorization Bypass und Information Disclosure.
Häufige Schwachstellen in GraphQL
1. Query-Depth-/Complexity-Angriffe
Tief verschachtelte Queries können einen DoS verursachen, indem sie übermäßig Ressourcen verbrauchen:
query MaliciousQuery {
user(id: "1") {
posts {
comments {
author {
posts {
comments {
author {
posts {
# ... unendlich verschachtelt
}
}
}
}
}
}
}
}
}
2. Introspection-Missbrauch
In der Produktion aktivierte Introspection legt das vollständige Schema offen und erleichtert die Reconnaissance:
query IntrospectionQuery {
__schema {
types {
name
fields {
name
type {
name
}
}
}
}
}
3. Fehlerhafte Autorisierung
Die Autorisierung muss in den Resolvern erfolgen, nicht nur in den Top-Level-Queries. IDOR tritt häufig auf, wenn die Autorisierung bei verschachtelten Feldern nicht geprüft wird.
4. Injection-Angriffe
GraphQL ist nicht immun gegen SQLi oder NoSQLi, wenn Eingaben in den Resolvern nicht bereinigt werden.
Wesentliche Schutzmaßnahmen
Query-Depth-Begrenzung
// Apollo-Server-Beispiel
import depthLimit from 'graphql-depth-limit';
const server = new ApolloServer({
typeDefs,
resolvers,
validationRules: [depthLimit(5)] // Max. Tiefe 5
});
Query-Complexity-Analyse
import { createComplexityLimitRule } from 'graphql-validation-complexity';
const server = new ApolloServer({
validationRules: [
createComplexityLimitRule(1000, {
scalarCost: 1,
objectCost: 5,
listFactor: 10
})
]
});
Rate Limiting
- Query-basiert: Queries pro Minute und Benutzer begrenzen
- Complexity-basiert: Budget an Complexity Points
- Kostenanalyse: Jedem Feld Kosten zuweisen
Autorisierung in GraphQL
Autorisierung auf Feldebene
const resolvers = {
Query: {
user: async (parent, { id }, context) => {
// Autorisierung auf Query-Ebene
if (!context.user) {
throw new AuthenticationError('Not authenticated');
}
return getUserById(id);
}
},
User: {
email: (user, args, context) => {
// Autorisierung auf Feldebene
if (context.user.id !== user.id && !context.user.isAdmin) {
return null; // E-Mail vor anderen Benutzern verbergen
}
return user.email;
},
ssn: (user, args, context) => {
// Extrem sensibles Feld
if (!context.user.isAdmin) {
throw new ForbiddenError('Admin only');
}
return user.ssn;
}
}
};
Direktiven-basierte Autorisierung
type User @auth(requires: AUTHENTICATED) {
id: ID!
username: String!
email: String! @auth(requires: OWNER_OR_ADMIN)
ssn: String! @auth(requires: ADMIN)
}
Schutz der Introspection
const server = new ApolloServer({
typeDefs,
resolvers,
introspection: process.env.NODE_ENV !== 'production',
// Oder nach Rolle steuern
plugins: [{
requestDidStart() {
return {
didResolveOperation({ request, context }) {
if (request.operationName === 'IntrospectionQuery'
&& !context.user?.isAdmin) {
throw new ForbiddenError('Introspection disabled');
}
}
}
}
}]
});
Eingabevalidierung
- Schema-Validierung: GraphQL validiert Typen automatisch
- Custom Scalars: Email, URL, DateTime mit Validierung
- Eingabebereinigung: Eingaben bereinigen, bevor sie in Resolvern verwendet werden
- Parametrisierte Queries: Prepared Statements in der Datenbank verwenden
Batching und DataLoader
Das N+1-Problem verhindern, das für einen DoS ausgenutzt werden kann:
import DataLoader from 'dataloader';
const userLoader = new DataLoader(async (userIds) => {
const users = await getUsersByIds(userIds);
return userIds.map(id => users.find(u => u.id === id));
});
const resolvers = {
Post: {
author: (post, args, { userLoader }) => {
return userLoader.load(post.authorId); // Gebündelt!
}
}
};
Monitoring und Logging
- Query-Logging: Alle Queries mit Metadaten protokollieren (Benutzer, IP, Zeit)
- Error Tracking: Sentry, Datadog für Exceptions
- Performance-Monitoring: Apollo Studio, GraphQL Hive
- Anomalieerkennung: Bei verdächtigen Queries alarmieren (zu komplex usw.)
Sicherheitswerkzeuge
- GraphQL Armor: Security-Middleware-Suite
- graphql-shield: Permissions-Layer mit Regeln
- InQL: Burp-Suite-Erweiterung für GraphQL-Pentesting
- BatchQL: Security-Testing-Tool für GraphQL
- graphql-cop: Security-Auditing-Tool
OWASP GraphQL Top 10
- Broken Object Level Authorization
- Broken Authentication
- Excessive Data Exposure
- Resource Exhaustion
- Broken Function Level Authorization
- Mass Assignment
- Security Misconfiguration
- Injection
- Improper Assets Management
- Insufficient Logging & Monitoring
Sichere Entwicklungspraktiken
- Autorisierung in ALLEN Resolvern implementieren
- Introspection in der Produktion deaktivieren
- Query Depth und Complexity begrenzen
- Aggressives Rate Limiting
- DataLoader verwenden, um N+1 zu verhindern
- Eingaben vor der Verarbeitung bereinigen
- Umfassendes Logging implementieren
- Regelmäßige Sicherheitsaudits und Pentests
Abschließende Empfehlungen
GraphQL erfordert im Vergleich zu REST ein Umdenken in Sachen Sicherheit. Die Flexibilität des Clients verlangt robuste Verteidigungsmaßnahmen auf dem Server. Implementieren Sie Depth Limiting, Complexity-Analyse und Autorisierung auf Feldebene von Anfang an. Nutzen Sie Monitoring-Tools, um Missbrauchsmuster zu erkennen. Testen Sie regelmäßig mit spezialisierten Werkzeugen wie InQL und BatchQL.
