פתרון בעיות באימות JWT

כשבקשה שנשלחת מאפליקציית לקוח ל-API כוללת אסימון JWT‏ (JSON Web Token),‏ Extensible Service Proxy (ESP) מאמת את ה-JWT לפני שהוא שולח את הבקשה אל קצה העורף של ה-API. בדף הזה מוסבר איך לפתור בעיות אם אימות ה-JWT נכשל ו-ESP מחזיר שגיאה בתשובה ללקוח. מידע נוסף על JWT זמין ב-RFC 7519.

שגיאה: 401: Jwt issuer is not configured

מצב כזה יכול לקרות כשפורסים את ESPv2 ב-Cloud Run, והדגל --allow-unauthenticated לא נמצא בפקודה gcloud run deploy. אם לא משתמשים בדגל, אסימון ה-JWT נחטף ומאומת על ידי שרת IAM של בקרת הגישה של Cloud Run ולא על ידי ESPv2. יכול להיות ש-IAM ישתמש במנפיק שונה מזה של ESPv2. </a=">

שגיאה: BAD_FORMAT

כדאי לבדוק את הדברים הבאים:

  • מוודאים ש-JWT מכיל JSON תקין.
  • בודקים שלכותרת ה-JWT יש את השדה "alg" והוא מוגדר לאחד מהערכים הבאים: "RS256",‏ "HS256",‏ "RS384",‏ "HS384",‏ "RS512" או "HS512".
  • בודקים את סוג הנתונים של השדות הבאים (אם הם קיימים) במטען הייעודי של ה-JWT:
    • ההצהרות "iat" (זמן ההנפקה), "exp" (זמן התפוגה) ו-"nbf"(לא לפני) הן מספרים גדולים מ-0 ולא מחרוזות.
    • השדות "sub" (נושא), "iss" (מונפק על ידי) ו"jti" (מזהה JWT) הם מחרוזות.
    • הטענה "aud" (קהל) היא מחרוזת או מערך של מחרוזות.
  • מוודאים שההצהרות הבאות מופיעות במטען הייעודי (payload) של JWT: "sub" (נושא), "iss" (מנפיק) ו-"aud" (קהל).

הנה דוגמה לאסימון JWT מפוענח שתקף:

{
  "alg": "RS256",
  "typ": "JWT",
  "kid": "42ba1e234ac91ffca687a5b5b3d0ca2d7ce0fc0a"
}

Payload:
{
  "iss": "myservice@myproject.iam.gserviceaccount.com",
  "iat": 1493833746,
  "aud": "myservice.appspot.com",
  "exp": 1493837346,
  "sub": "myservice@myproject.iam.gserviceaccount.com"
}
שגיאה: TIME_CONSTRAINT_FAILURE

משתמשים ב-jwt.io כדי לפענח את ה-JWT ולוודא ש:

  • ההצהרה "exp" (זמן התפוגה) קיימת.
  • ערך הטענה "exp" (זמן התפוגה) הוא תאריך ושעה בעתיד. התאריך והשעה הנוכחיים צריכים להיות לפני תאריך התפוגה והשעה שמופיעים בתביעה "exp".
  • הטענה "nbf" (לא לפני) (אם היא קיימת) היא תאריך ושעה בעבר. התאריך והשעה הנוכחיים צריכים להיות מאוחרים או שווים לתאריך ולשעה שמופיעים בתביעת זכויות היוצרים "nbf".
שגיאה: UNKNOWN

משתמשים ב-jwt.io כדי לפענח את ה-JWT ולוודא ש:

  • אם טענת "iss" (המנפיק) היא כתובת אימייל, טענות "sub" (הנושא) ו-"iss" צריכות להיות זהות. כך אפשר לוודא שיוצרי האימיילים ינפיקו את אסימון ה-JWT בעצמם.

שגיאה: KEY_RETRIEVAL_ERROR

  • צריך לוודא שה-URI של המפתח הציבורי שצוין בשדה x-google-jwks_uri במסמך OpenAPI תקין ותקף.

שגיאה: Issuer not allowed

  • צריך לוודא שההצהרה "iss" (מנפיק) בטוקן ה-JWT זהה לשדה x-google-issuer בקטע securityDefinitions של אובייקט האבטחה במסמך OpenAPI.

  • במסמך OpenAPI, בודקים שאובייקט האבטחה מופעל עבור שיטת ה-API שהופעלה.

בדוגמה של קובץ openapi.yaml אפשר לראות איך מתארים אבטחה ברמת השיטה באמצעות אובייקטים של securityDefinition ו-security.

שגיאה: Audience not allowed

משווים את הצהרת "aud" (קהל) באסימון JWT כדי לראות אם היא תואמת לשם השירות של Endpoints, שמתאים לשדה host במסמך OpenAPI.

אם ההצהרה "aud" ושם השירות של Endpoints שונים:

  • בודקים שהצהרת "aud" ב-JWT תואמת לאחד מהערכים של x-google-audiences שצוינו במסמך OpenAPI.

  • מוודאים ש-x-google-audiences ו-x-google-issuer נמצאים באותו אובייקט securityDefinitions במסמך OpenAPI.

אם הצהרת "aud" ושם שירות ה-Endpoints זהים, ה-ESP מאמת את קהל היעד ומתעלם מהערכים של x-google-audiences במסמך OpenAPI. לדוגמה, אם שם השירות הוא "myservice.endpoints.example-project-12345.cloud.goog", אז JWT עם "aud" שמוגדר ל-"myservice.endpoints.example-project-12345.cloud.goog" או ל-"https://myservice.endpoints.example-project-12345.cloud.goog" הוא קהל תקף.