אבטחת GraphQL
GraphQL מציע גמישות עוצמתית אך מכניס וקטורי תקיפה ייחודיים: התקפות query complexity, ניצול לרעה של introspection, עקיפת הרשאה וחשיפת מידע.
פגיעויות נפוצות ב-GraphQL
1. התקפות Query Depth / Complexity
שאילתות מקוננות לעומק עלולות לגרום ל-DoS על ידי צריכת משאבים מופרזת:
query MaliciousQuery {
user(id: "1") {
posts {
comments {
author {
posts {
comments {
author {
posts {
# ... מקונן עד אינסוף
}
}
}
}
}
}
}
}
}
2. ניצול לרעה של Introspection
introspection מופעל בסביבת ייצור חושף את הסכמה המלאה ומקל על reconnaissance:
query IntrospectionQuery {
__schema {
types {
name
fields {
name
type {
name
}
}
}
}
}
3. הרשאה שבורה
הרשאה חייבת להתבצע ב-resolvers, ולא רק בשאילתות ברמה העליונה. IDOR נפוץ כאשר ההרשאה אינה נבדקת בשדות מקוננים.
4. התקפות Injection
GraphQL אינו חסין מפני SQLi או NoSQLi אם הקלטים אינם עוברים סניטציה ב-resolvers.
הגנות חיוניות
הגבלת Query Depth
// דוגמה ל-Apollo Server
import depthLimit from 'graphql-depth-limit';
const server = new ApolloServer({
typeDefs,
resolvers,
validationRules: [depthLimit(5)] // עומק מרבי 5
});
ניתוח Query Complexity
import { createComplexityLimitRule } from 'graphql-validation-complexity';
const server = new ApolloServer({
validationRules: [
createComplexityLimitRule(1000, {
scalarCost: 1,
objectCost: 5,
listFactor: 10
})
]
});
Rate Limiting
- מבוסס שאילתות: הגבלת שאילתות לדקה לכל משתמש
- מבוסס complexity: תקציב של complexity points
- ניתוח עלות: הקצאת עלות לכל שדה
הרשאה ב-GraphQL
הרשאה ברמת השדה
const resolvers = {
Query: {
user: async (parent, { id }, context) => {
// הרשאה ברמת ה-query
if (!context.user) {
throw new AuthenticationError('Not authenticated');
}
return getUserById(id);
}
},
User: {
email: (user, args, context) => {
// הרשאה ברמת השדה
if (context.user.id !== user.id && !context.user.isAdmin) {
return null; // הסתרת האימייל ממשתמשים אחרים
}
return user.email;
},
ssn: (user, args, context) => {
// שדה רגיש במיוחד
if (!context.user.isAdmin) {
throw new ForbiddenError('Admin only');
}
return user.ssn;
}
}
};
הרשאה מבוססת directives
type User @auth(requires: AUTHENTICATED) {
id: ID!
username: String!
email: String! @auth(requires: OWNER_OR_ADMIN)
ssn: String! @auth(requires: ADMIN)
}
הגנה על Introspection
const server = new ApolloServer({
typeDefs,
resolvers,
introspection: process.env.NODE_ENV !== 'production',
// או שליטה לפי role
plugins: [{
requestDidStart() {
return {
didResolveOperation({ request, context }) {
if (request.operationName === 'IntrospectionQuery'
&& !context.user?.isAdmin) {
throw new ForbiddenError('Introspection disabled');
}
}
}
}
}]
});
אימות קלט
- אימות סכמה: GraphQL מאמת טיפוסים באופן אוטומטי
- Custom scalars: Email, URL, DateTime עם אימות
- סניטציית קלט: ביצוע סניטציה לקלטים לפני שימוש בהם ב-resolvers
- שאילתות פרמטריות: שימוש ב-prepared statements במסד הנתונים
Batching ו-DataLoader
מניעת בעיית ה-N+1, שעלולה להיות מנוצלת ל-DoS:
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); // באצ'!
}
}
};
ניטור ורישום (Logging)
- רישום שאילתות: תיעוד כל השאילתות עם metadata (משתמש, IP, זמן)
- מעקב שגיאות: Sentry, Datadog עבור exceptions
- ניטור ביצועים: Apollo Studio, GraphQL Hive
- זיהוי אנומליות: התרעה על שאילתות חשודות (מורכבות מדי וכו')
כלי אבטחה
- GraphQL Armor: חבילת middleware לאבטחה
- graphql-shield: שכבת הרשאות עם rules
- InQL: תוסף Burp Suite ל-pentest של GraphQL
- BatchQL: כלי security testing ל-GraphQL
- graphql-cop: כלי security auditing
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
פרקטיקות פיתוח מאובטח
- יישום הרשאה בכל ה-resolvers
- השבתת introspection בסביבת ייצור
- הגבלת query depth ו-complexity
- rate limiting אגרסיבי
- שימוש ב-DataLoader למניעת N+1
- סניטציה לקלטים לפני עיבוד
- יישום logging מקיף
- ביקורות אבטחה ו-pentests סדירים
המלצות לסיכום
GraphQL דורש שינוי בתפיסת האבטחה בהשוואה ל-REST. הגמישות של ה-client מחייבת הגנות חזקות בצד ה-server. ישמו depth limiting, ניתוח complexity והרשאה ברמת השדה כבר מההתחלה. השתמשו בכלי ניטור לזיהוי דפוסי ניצול לרעה. בדקו באופן קבוע עם כלים ייעודיים כמו InQL ו-BatchQL.
