“זה GraphQL, זה Typed, זה סגור” – שאילתת introspection אחת אחר כך

Read this article in English

עושים בדיקת אבטחה למערכת SaaS מוכרת, עם API מסוג GraphQL. הצוות שם אומר: “אנחנו בטוחים – GraphQL זה Typed, הכל סגור.” אני מחייך – שמעתי את זה לא פעם.

שלב ראשון: מיפוי. ב-REST מחפשים Swagger, וב-GraphQL משתמשים ב-introspection:

{ __schema { types { name fields { name } } } }

השרת עונה יפה, ועכשיו יש לי blueprint מלא – כל הטייפים, כל המיוטיישנים.

שלב שני: חיפוש נקודה מעניינת. בין כל המיוטיישנים מופיע משהו בשם updateUser עם השדות: id, isAdmin, email, name. ה-UI הרגיל מאפשר לשנות רק שם ומייל. אני שואל את עצמי: “מה קורה אם אשלח mutation עם isAdmin=true?”

אני מריץ:

mutation { updateUser(id: 6, isAdmin: true) { id isAdmin } }

והתגובה:

{ "data": { "updateUser": { "id": 6, "isAdmin": true } } }

בום – המשתמש שלי עכשיו אדמין.

לא צריך לפרוץ את האפליקציה או לנחש סיסמאות. המערכת עצמה, עם הרשאות משתמש רגיל, מאפשרת עדכון של שדה קריטי שלא נבדק ברמת הרשאות. ה-UI מסתיר את זה, אבל ה-API עצמו לא חסום.

ההמלצות

  • לחסום introspection ב-Production.
  • להגדיר בדיקות הרשאות ברמת שדה, לא רק “משתמש משנה את עצמו”.
  • להריץ בדיקות אוטומטיות על כל mutation חדש – במיוחד כאלה שמשנים הרשאות.

מוסר השכל: שאילתת introspection אחת ושורת mutation אחת – זה כל מה שנדרש כדי לפתוח דלת לאדמין. לא כי GraphQL בעייתי, אלא כי הנחת האבטחה הייתה “אם זה לא ב-UI, זה בטוח”.


פוסט זה פורסם לראשונה בלינקדאין בתאריך 2025-07-28. — ארז מטולה