סקירה כללית של מדיניות JWS ו-JWT

הדף הזה רלוונטי ל-Apigee ול-Apigee Hybrid.

לעיון במסמכי התיעוד של Apigee Edge

במאמר הזה מוסבר על JWT (‏JSON Web Token) ו-JWS (‏JSON Web Signature) ועל כללי המדיניות של Apigee JWS/JWT.

גם JWS וגם JWT משמשים בדרך כלל לשיתוף טענות או הצהרות בין אפליקציות מקושרות. כללי המדיניות של JWS/JWT מאפשרים ל-API proxies של Apigee:

  • יוצרים JWT חתום או JWS, או JWT מוצפן.
  • אימות של JWT חתום או JWS, או JWT מוצפן, ואימות הצהרות נבחרות ב-JWS או ב-JWT.
  • פענוח של JWT חתום או מוצפן או של JWS בלי לאמת את החתימה או לפענח את ה-JWT או ה-JWS המוצפנים. במקרה של JWS, המדיניות DecodeJWS יכולה לפענח רק את הטענות בכותרת של ה-JWS. במקרה של JWT מוצפן, המדיניות DecodeJWT יכולה לפענח רק את הכותרת הלא מוצפנת.

בשני המקרים האחרונים, המדיניות גם מגדירה משתני זרימה. כך מדיניות עוקבת בתהליך העבודה של Apigee יכולה לבדוק את הטענות ב-JWT או ב-JWS, ולקבל החלטות על סמך הטענות האלה, או להעביר את המידע הזה לשירותי הקצה העורפי.

כשמשתמשים במדיניות VerifyJWS או VerifyJWT, בקשת JWS/JWT לא תקינה תידחה ותגרום לשגיאה. באופן דומה, כשמשתמשים במדיניות DecodeJWS או DecodeJWT, בקשת JWS/JWT פגומה תגרום לשגיאה.

תרחישים לדוגמה

אפשר להשתמש במדיניות JWS/JWT כדי:

  • יוצרים JWS/JWT חדש בצד ה-proxy או בצד נקודת הקצה של היעד ב-proxy של Apigee. לדוגמה, אפשר ליצור זרימת בקשות ל-proxy שיוצרת JWS/JWT ומחזירה אותו ללקוח. לחלופין, אפשר לעצב שרת proxy כך שיפיק JWS/JWT בתהליך הבקשה של היעד, ויצרף אותו לבקשה שנשלחת ליעד. אחרי זה, ה-JWS/JWT והטענות שלו יהיו זמינים כדי לאפשר לשירותי קצה עורפי לבצע עיבוד אבטחה נוסף.
  • מאמתים ומחלצים הצהרות מ-JWS/JWT שהתקבלו מבקשות לקוח נכנסות, מתגובות של שירות היעד, מתגובות של מדיניות Service Callout או ממקורות אחרים. כדי לאמת חתימה של JWS/JWT חתום, Apigee ישתמש באחד מהאלגוריתמים RSA,‏ ECDSA או HMAC, בין אם ה-JWS/JWT נוצר על ידי Apigee או על ידי צד שלישי. כדי לפענח JWT מוצפן, Apigee יפענח את ה-JWT באמצעות אחד מאלגוריתמי ההצפנה הנתמכים של JWA (ראו IETF RFC 7518).
  • פענוח של JWS/JWT. הפענוח הכי שימושי כשמשתמשים בו יחד עם מדיניות האימות של JWS/JWT, במקרים שבהם צריך לדעת את הערך של הצהרה (JWT) או כותרת (JWS/JWT) בתוך JWS/JWT לפני שמאמתים JWS/JWT חתום או מפענחים JWT מוצפן.

החלקים של JWS/JWT

ב-JWS או ב-JWT חתומים, המידע מקודד בשלושה חלקים שמופרדים באמצעות נקודות:

Header.Payload.Signature
  • המדיניות Generate JWS/JWT יוצרת את כל שלושת החלקים.
  • המדיניות Verify JWS/JWT בודקת את כל שלושת החלקים.
  • מדיניות DecodeJWS בודקת רק את הכותרת. המדיניות DecodeJWT בודקת רק את הכותרת ואת המטען הייעודי (payload).

בנוסף, JWS תומך בפורמט מנותק שבו מטען הייעודי (payload) מושמט מ-JWS:

Header..Signature

ב-JWS מנותק, המטען הייעודי (payload) נשלח בנפרד מה-JWS. משתמשים ברכיב <DetachedContent> של מדיניות Verify JWS כדי לציין את מטען ה-JWS הגולמי שלא עבר קידוד. לאחר מכן, מדיניות האימות של JWS מאמתת את ה-JWS באמצעות הכותרת והחתימה ב-JWS והמטען הייעודי (payload) שצוין ברכיב <DetachedContent>.

ב-JWT מוצפן, המידע מקודד בחמישה חלקים שמופרדים בנקודות:

Header.Key.InitializationVector.Payload.AuthenticationTag

כללי המדיניות GenerateJWT ו-VerifyJWT יוצרים את כל החלקים האלה או בודקים אותם. הפונקציה DecodeJWT יכולה לבדוק רק את הכותרת הלא מוצפנת.

מידע נוסף על אסימונים, על הקידוד שלהם ועל החתימה או ההצפנה שלהם זמין במסמכי התקנים הרלוונטיים:

ההבדלים בין JWS לבין JWT

אפשר להשתמש ב-JWT או ב-JWS כדי לשתף טענות או הצהרות בין אפליקציות מקושרות. ההבדל העיקרי בין השניים הוא הייצוג של מטען הייעודי (payload):

  • JWT
    • המטען הייעודי הוא תמיד אובייקט JSON.
    • המטען הייעודי (payload) תמיד מצורף ל-JWT.
    • הכותרת typ של הטוקן תמיד מוגדרת ל-JWT.
    • יכול להיות שהמטען הייעודי חתום או מוצפן.
  • JWS
    • המטען הייעודי יכול להיות מיוצג בכל פורמט, כמו אובייקט JSON, זרם בייטים, זרם אוקטט ועוד.
    • המטען הייעודי לא חייב להיות מצורף ל-JWS.
    • הכותרת והמטען הייעודי תמיד חתומים. JWS לא תומך בהצפנה.

מכיוון שפורמט ה-JWT תמיד משתמש באובייקט JSON כדי לייצג את המטען הייעודי (payload), למדיניות GenerateJWT ו-VerifyJWT של Apigee יש תמיכה מובנית בטיפול בשמות נפוצים של הצהרות רשומות, כמו aud,‏ iss,‏ sub ועוד. כלומר, אפשר להשתמש ברכיבים של מדיניות GenerateJWT כדי להגדיר את הטענות האלה במטען הייעודי (payload), וברכיבים של מדיניות VerifyJWT כדי לאמת את הערכים שלהן. מידע נוסף זמין בקטע Registered Claim Names במפרט JWT.

בנוסף לתמיכה בשמות מסוימים של טענות רשומות, המדיניות GenerateJWT תומכת באופן ישיר בהוספת טענות עם שמות שרירותיים למטען הייעודי (payload) או לכותרת של ה-JWT. כל טענה היא זוג פשוט של שם/ערך, והערך יכול להיות מסוג number,‏ boolean,‏ string,‏ map או array.

כשמשתמשים בפונקציה GenerateJWS, צריך לספק משתנה הקשר שמייצג את המטען הייעודי (payload). מכיוון ש-JWS יכול להשתמש בכל ייצוג נתונים עבור המטען הייעודי (payload), אין מושג של 'טענת מטען ייעודי' ב-JWS, ומדיניות GenerateJWS לא תומכת בהוספת טענות עם שמות שרירותיים למטען הייעודי. אפשר להשתמש במדיניות GenerateJWS כדי להוסיף הצהרות עם שמות שרירותיים לכותרת של JWS. בנוסף, מדיניות JWS תומכת במטען ייעודי (payload) מנותק, שבו JWS משמיט את המטען הייעודי. מטען ייעודי מאפשר לשלוח את ה-JWS ואת המטען בנפרד. שימוש במטען ייעודי (payload) מנותק יכול להיות יעיל יותר מבחינת נפח, במיוחד במטענים ייעודיים גדולים, והוא נדרש על ידי כמה תקני אבטחה.

מניעת הזרקת תבניות כשמשתמשים ב-JWS וב-JWT

כדי למנוע חשיפה לא מורשית של נתונים, צריך לפעול לפי ההנחיות הבאות כשמשתמשים במדיניות GenerateJWT או GenerateJWS:

  • אל תשתמשו בהפניות ישירות לקלט של משתמשים: אל תשתמשו לעולם בקלט לא מהימן (כמו request.queryparam.* או request.header.*) ישירות במאפיין ref שתומך בתבניות.
  • ניקוי קלט: אם אתם חייבים להשתמש בנתונים חיצוניים בהצהרת JWT/JWS, קודם צריך להשתמש במדיניות AssignMessage כדי להסיר מהקלט סוגריים מסולסלים ({ }) או תווים אחרים של תבנית לפני שמתייחסים אליו.
  • שימוש בטענות מפורשות למחרוזות: לטענות פשוטות של מחרוזות, מומלץ להימנע משימוש ב-type="map". שימוש ב-type="string" שמוגדר כברירת מחדל מונע יצירת תבנית משתמעת של הערך שאליו מתייחסים.
  • שימו לב לחוסר העקביות בהתנהגות בין מדיניות האימות למדיניות היצירה: מדיניות יצירת JWS ו-JWT מתנהגת באופן שונה ממדיניות האימות בנוגע ליצירת תבניות.

חתימה לעומת הצפנה

‫Apigee יכול ליצור JWT חתום או מוצפן. בוחרים ב-JWT חתום אם המטען הייעודי (payload) לא צריך להיות סודי, אבל חשוב לספק לקוראים ערבויות לשלמות ולמניעת כפירה. JWT חתום מבטיח לקוראים שהמטען הייעודי לא השתנה מאז שה-JWT נחתם, ושה-JWT נחתם על ידי בעל המפתח הפרטי. בוחרים ב-JWT מוצפן אם המטען הייעודי צריך להיות סודי. JWT מוצפן מספק סודיות למטען הייעודי, כי רק בעל המפתח המתאים יכול לפענח אותו.

אפשר להשתמש גם ב-JWT מוצפן וגם ב-JWT חתום, במיוחד אם ה-JWT המוצפן משתמש באלגוריתם קריפטוגרפי אסימטרי (RSA, ‏ ECDSA). במקרה כזה, אי אפשר לקבוע את הזהות של יוצר ה-JWT, כי מפתח ההצפנה הוא ציבורי. כדי לפתור את הבעיה הזו, צריך לשלב חתימה עם הצפנה. דוגמה אופיינית:

  • חתימה על מטען ייעודי (payload) כדי ליצור JWS או JWT חתום.
  • מצפינים את התוצאה החתומה כדי ליצור JWT מוצפן.

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

אלגוריתמים של חתימות

במקרה של JWT חתום, מדיניות האימות של JWS/JWT ומדיניות היצירה של JWS/JWT תומכות באלגוריתמים RSA,‏ RSASSA-PSS,‏ ECDSA ו-HMAC, באמצעות סכומי ביקורת של SHA2 בעוצמת סיביות של 256,‏ 384 או 512. מדיניות DecodeJWS ו-DecodeJWT פועלת ללא קשר לאלגוריתם ששימש לחתימה על JWS/JWT.

אלגוריתמים של HMAC

אלגוריתמי ה-HMAC מסתמכים על סוד לשימוש עם טוקן צרכן, שנקרא המפתח הסודי, כדי ליצור את החתימה (שנקראת גם חתימה על JWS או JWT) וכדי לאמת את החתימה.

אורך מפתח הסוד המינימלי תלוי בחוזק הביטים של האלגוריתם:

  • ‫HS256: אורך מפתח מינימלי של 32 בייט
  • ‫HS384: אורך מפתח מינימלי של 48 בייט
  • ‫HS512: אורך המפתח המינימלי הוא 64 בייטים

אלגוריתמים של RSA

אלגוריתמי ה-RSA משתמשים בזוג מפתחות ציבורי/פרטי לחתימה הקריפטוגרפית. במפרט JWA נעשה שימוש בשמות RS256,‏ RS384 ו-RS512 כדי לייצג את האפשרויות האלה. בחתימות RSA, הצד החותם משתמש במפתח פרטי של RSA כדי לחתום על JWS/JWT, והצד המאמת משתמש במפתח ציבורי תואם של RSA כדי לאמת את החתימה על JWS/JWT. אין דרישות לגבי גודל המפתחות.

אלגוריתמים של RSASSA-PSS

אלגוריתמי RSASSA-PSS הם עדכון של אלגוריתמי RSA, והם משתמשים בשמות PS256,‏ PS384 ו-PS512. בדומה לגרסאות RS*, אלגוריתמי RSASSA-PSS משתמשים בזוג מפתחות RSA ציבורי/פרטי לחתימה הקריפטוגרפית. הפורמט, המנגנון ומגבלות הגודל של המפתח זהים לאלה של אלגוריתמי RS*.

אלגוריתמים של ECDSA

קבוצת האלגוריתמים של אלגוריתם החתימה הדיגיטלית של עקומים אליפטיים (ECDSA) הם אלגוריתמים של הצפנה המבוססת על עקומים אליפטיים עם עקומת P-256,‏ P-384 או P-521. כשמשתמשים באלגוריתמים של ECDSA, האלגוריתם קובע את סוג המפתח הציבורי והפרטי שצריך לציין:

אלגוריתם עקומה דרישה מרכזית
ES256 P-256 מפתח שנוצר מהעקומה P-256 (שנקראת גם secp256r1 או prime256v1)
ES384 P-384 מפתח שנוצר מהעקומה P-384 (נקרא גם secp384r1)
ES512 P-521 מפתח שנוצר מעקומת P-521 (נקראת גם secp521r1)

אלגוריתמים להצפנה

כשמשתמשים בפונקציות GenerateJWT ו-VerifyJWT כדי לטפל ב-JWT מוצפן, המדיניות תומכת באלגוריתמים הבאים:

  • dir
  • RSA-OAEP-256
  • A128KW, ‏ A192KW, ‏ A256KW
  • A128GCMKW, A192GCMKW, A256GCMKW
  • ‫PBES2-HS256+A128KW, ‏ PBES2-HS384+A192KW, ‏ PBES2-HS512+A256KW
  • ‪ECDH-ES, ECDH-ES+A128KW, ECDH-ES+A192KW, ECDH-ES+A256KW

מקשים וייצוגים של מקשים

תקני JOSE, שכוללים JWS,‏ JWT חתום ומוצפן ועוד, מתארים איך להשתמש במפתחות קריפטוגרפיים כדי לחתום על מידע או להצפין אותו. הרכיבים הבסיסיים של כל פעולה קריפטוגרפית כוללים את האלגוריתם ואת המפתח. אלגוריתמים שונים דורשים סוגים שונים של מפתחות, ובמקרים מסוימים, גדלים שונים של מפתחות.

אלגוריתמים סימטריים, כמו משפחת HS* לחתימה או אלגוריתם A128KW להצפנה, דורשים מפתחות סימטריים או משותפים: אותו מפתח משמש לחתימה ולאימות, או שאותו מפתח משמש להצפנה ולפענוח. אלגוריתמים אסימטריים, כמו אלגוריתמי RS*,‏ PS* ו-ES* לחתימה, או אלגוריתמי ECDH* להצפנה, משתמשים בזוגות מפתחות – יש מפתח ציבורי ומפתח פרטי, והם תואמים. במהלך החתימה, החותם משתמש במפתח הפרטי כדי לחתום, וכל צד יכול להשתמש במפתח הציבורי כדי לאמת את החתימה. בהצפנה, המצפין משתמש במפתח הציבורי כדי להצפין, והמפענח משתמש במפתח הפרטי כדי לפענח. מפתחות ציבוריים, כמו שהשם שלהם מרמז, ניתנים לשיתוף עם כולם, ולא צריך לשמור אותם בסוד.

יש דרכים שונות לסדר מפתחות קריפטוגרפיים בפורמט טקסט. מדיניות Apigee מקבלת מפתחות שעברו סריאליזציה בצורות שונות: פורמט מקודד PEM, פורמט JWKS או, במקרה של מפתחות משותפים, פורמט מקודד UTF-8 או פורמט מקודד base64.

פורמט PEM

בדרך כלל משתמשים בקידוד PEM למפתחות ציבוריים או פרטיים, כפי שמוגדר ב-IETF RFC 7468. דוגמה למפתח פרטי בפורמט PEM:

-----BEGIN PRIVATE KEY-----
MIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQgVcB/UNPxalR9zDYAjQIf
jojUDiQuGnSJrFEEzZPT/92hRANCAASc7UJtgnF/abqWM60T3XNJEzBv5ez9TdwK
H0M6xpM2q+53wmsN/eYLdgtjgBd3DBmHtPilCkiFICXyaA8z9LkJ
-----END PRIVATE KEY-----

יש פורמטים דומים של PEM למפתחות ציבוריים או למפתחות פרטיים מוצפנים.

פורמט JWKS

‫JSON Web Key‏ (JWK) הוא מבנה נתונים בפורמט JSON שמייצג מפתח קריפטוגרפי יחיד. ‫JSON Web Key Set‏ (JWKS) הוא מבנה JSON שמייצג קבוצה של JWK. הפורמטים JWK ו-JWKS מתוארים ב-RFC7517. דוגמאות ל-JWKS מופיעות בנספח א': דוגמאות ל-JSON Web Key Sets.

הפורמט JWKS נועד לאפשר לכל צד לייצג קבוצה של מפתחות בפורמט סטנדרטי. תרחיש שימוש מרכזי הוא שיתוף מפתחות ציבוריים באופן סטנדרטי, באמצעות נקודת קצה של HTTP שמספקת נתונים בפורמט JWKS. כשחברה או מערכת שיוצרות חתימות JWS או JWT, כמו ספק זהויות, מפרסמות את המפתחות הציבוריים שלהן, כל מערכת או אפליקציה שיכולות לקרוא את המפתחות הציבוריים יכולות לאמת חתימות שנוצרו על ידי הצד החותם. לעומת זאת, כל מערכת או אפליקציה שרוצות להצפין נתונים שצריכים להיות לקריאה בלבד על ידי צד או חברה מסוימים, יכולות לאחזר את המפתחות הציבוריים ששייכים לצד או לחברה האלה, וליצור JWT מוצפן למטרה הזו.

במסמך RFC7517 מתוארים הרכיבים העיקריים של מפתח JWKS לכל סוג מפתח, כמו RSA או EC. הרכיבים האלה צריכים תמיד להיות נוכחים:

  • kty – סוג המפתח, כמו RSA או EC.
  • kid – מזהה המפתח. הערך יכול להיות כל מחרוזת ייחודית שרירותית. לא יכולים להיות כפילויות בתוך קבוצת מפתחות יחידה. אם ל-JWT הנכנס יש מזהה מפתח שקיים בקבוצת ה-JWKS, המדיניות VerifyJWS או VerifyJWT תשתמש במפתח הציבורי הנכון כדי לאמת את החתימה של ה-JWS או ה-JWT.

הנה דוגמאות לרכיבים אופציונליים ולערכים שלהם:

  • alg: אלגוריתם המפתח. הוא צריך להיות זהה לאלגוריתם החתימה ב-JWS/JWT.
  • use: השימוש המיועד במפתח. ערכים אופייניים הם sig לחתימה ולאימות, או enc להצפנה ולפענוח.

ה-JWKS הבא (שנשלף במקור מ-https://www.googleapis.com/oauth2/v3/certs, אבל הוא לא עדכני עכשיו) כולל את הרכיבים והערכים הנדרשים, ואפשר להשתמש בו ב-Apigee:‏

{
     "keys":[
        {
           "kty":"RSA",
           "alg":"RS256",
           "use":"sig",
           "kid":"ca04df587b5a7cead80abee9ea8dcf7586a78e01",
           "n":"iXn-WmrwLLBa-QDiToBozpu4Y4ThKdwORWFXQa9I75pKOvPUjUjE2Bk05TUSt7-V7KDjCq0_Nkd-X9rMRV5LKgCa0_F8YgI30QS3bUm9orFryrdOc65PUIVFVxIwMZuGDY1hj6HEJVWIr0CZdcgNIll06BasclckkUK4O-Eh7MaQrqb646ghFlG3zlgk9b2duHbDOq3s39ICPinRQWC6NqTYfqg7E8GN_NLY9srUCc_MswuUfMJ2cKT6edrhLuIwIj_74YGkpOwilr2VswKsvJ7dcoiJxheKYvKDKtZFkbKrWETTJSGX2Xeh0DFB0lqbKLVvqkM2lFU2Qx1OgtTnrw",
           "e":"AQAB"
        },
        {
            "kty":"EC",
            "alg":"ES256",
            "use":"enc",
            "kid":"k05TUSt7-V7KDjCq0_N"
            "crv":"P-256",
            "x":"Xej56MungXuFZwmk_xccvsMpCtXmqhvEEMCmHyAmKF0",
            "y":"Bozpu4Y4ThKdwORWFXQa9I75pKOvPUjUjE2Bk05TUSt",
        }
     ]
  }
  

ציון מפתחות במדיניות JWS ו-JWT

בין אם אתם יוצרים או מאמתים JWS או JWT, אתם צריכים לספק מפתח לשימוש בפעולות הקריפטוגרפיות.

כשיוצרים JWT חתום, צריך לספק מפתח שיכול ליצור את החתימה.

  • במקרה של אלגוריתם חתימה מסוג RS*,‏ PS* או ES*, שכולם משתמשים במפתחות אסימטריים, צריך לספק את המפתח הפרטי כדי ליצור את החתימה.
  • במקרה של אלגוריתם HS*, צריך לספק את המפתח הסימטרי שישמש ליצירת החתימה.

כשמאמתים JWS או JWT חתומים, צריך לספק מפתח שיכול לאמת את החתימה.

  • במקרה של אלגוריתם חתימה מסוג RS*,‏ PS* או ES*, צריך לספק את המפתח הציבורי שמשויך למפתח הפרטי ששימש במקור לחתימה על האסימון.
  • במקרה של אלגוריתם HS*, צריך לספק את אותו מפתח סימטרי ששימש לחתימה על JWS או JWT.

יש שתי אפשרויות לספק את המפתחות למדיניות JWS ו-JWT:

  • לספק את ערך המפתח ישירות (בדרך כלל באמצעות משתנה הקשר), או
  • מספקים את המפתח בעקיפין, באמצעות kid ו-JWKS. אפשר לציין את ה-JWKS ישירות או בעקיפין באמצעות כתובת URL של HTTP שדרכה Apigee יכול לאחזר את ה-JWKS.

בדרך כלל משתמשים באפשרות של כתובת URL של JWKS רק כמקור של מפתחות ציבוריים שאפשר להשתמש בהם עם אלגוריתמים אסימטריים, כי כתובות URL של JWKS הן בדרך כלל ציבוריות.

בדוגמאות הבאות אפשר לראות איך אפשר לספק מפתחות ישירות בתרחישים שונים.

  • יוצרים JWT חתום באמצעות אלגוריתם HS256. המפתח הנדרש במקרה הזה הוא מפתח סימטרי. המדיניות הזו מספקת משתנה הקשר שמכיל את המפתח הסודי בקידוד base64url.

    <GenerateJWT name='gen-138'>
      <Algorithm>HS256</Algorithm>
      <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
      <SecretKey encoding='base64url'>
        <Value ref='private.secretkey'/>
        <Id ref='variable-containing-desired-keyid'/>
      </SecretKey>
      . . .
      <OutputVariable>output_variable_name</OutputVariable>
    </GenerateJWT>
  • מאמתים JWT שנחתם באמצעות אלגוריתם HS256. המפתח הנדרש במקרה הזה הוא מפתח סימטרי. כמו בדוגמה שלמעלה, המדיניות הזו מספקת משתנה הקשר שמכיל את המפתח הסודי בקידוד base64url.

    <VerifyJWT name='verify-138'>
      <Algorithm>HS256</Algorithm>
      <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
      <SecretKey encoding='base64url'>
        <Value ref='private.secretkey'/>
      </SecretKey>
      . . .
      <OutputVariable>output_variable_name</OutputVariable>
    </VerifyJWT>
  • מאמתים JWT שנחתם באמצעות אלגוריתם PS256. המפתח הנדרש במקרה הזה הוא מפתח RSA ציבורי. המדיניות הזו מספקת משתנה הקשר שמכיל את המפתח הציבורי בקידוד PEM.

    <VerifyJWT name='JWT-001'>
      <Algorithm>PS256</Algorithm>
      <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
      <PublicKey>
        <Value ref='variable-containing-pem-encoded-public-key'/>
      </PublicKey>
      . . .
    </VerifyJWT>
  • יוצרים JWT שחתום באמצעות אלגוריתם PS256. המפתח שנדרש במקרה הזה הוא מפתח RSA פרטי. המדיניות הזו מספקת משתנה הקשר שמכיל את המפתח הפרטי בקידוד PEM.

    <GenerateJWT name='JWT-002'>
      <Algorithm>PS256</Algorithm>
      <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
      <PrivateKey>
        <Value ref='private.variable-containing-pem-encoded-private-key'/>
      </PrivateKey>
       . . .
    </GenerateJWT>

קובץ JWKS כמקור מפתח לאימות JWS או JWT חתום

כשמערכת או אפליקציה יוצרות JWS/JWT, בדרך כלל המערכת או האפליקציה מוסיפות מזהה מפתח (הצהרת kid) לכותרת של ה-JWS/JWT. המפתח מציין לכל מי שקורא את ה-JWS או ה-JWT איזה מפתח נדרש כדי לאמת את החתימה על ה-JWS או ה-JWT החתום, או כדי לפענח את ה-JWT המוצפן.

לדוגמה, נניח שרשות מנפיקה חותמת על JWT באמצעות מפתח פרטי. הערך של 'מזהה המפתח' מציין את המפתח הציבורי התואם שצריך להשתמש בו כדי לאמת את ה-JWT. רשימת המפתחות הציבוריים זמינה בדרך כלל בנקודת קצה מוכרת, כמו נקודת הקצה של Google Identity או אימות ב-Firebase. לספקים אחרים יהיו נקודות קצה ציבוריות משלהם שמפרסמות מפתחות בפורמט JWKS.

כשמשתמשים ב-Apigee כדי לאמת JWS או JWT חתום עם מפתחות ציבוריים שמשותפים דרך נקודת קצה של JWKS, יש כמה אפשרויות:

  • אפשרות 1: בהגדרת המדיניות, מציינים את ה-URI של נקודת הקצה של JWKS ברכיב <PublicKey/JWKS>. לדוגמה, במדיניות VerifyJWT:

    <VerifyJWT name="JWT-Verify-RS256">
      <Algorithm>RS256</Algorithm>
      <Source>json.jwt</Source>
      <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
      <PublicKey>
          <JWKS uri="https://www.googleapis.com/oauth2/v3/certs"/>
      </PublicKey>
      . . .
    </VerifyJWT>

    במקרה כזה, Apigee:

    1. בודקים את הכותרת של JWS/JWT כדי למצוא את אלגוריתם החתימה (alg), כמו RS256, ודוחים את ה-JWT הנכנס אם האלגוריתם הזה לא תואם לאלגוריתם שהוגדר במדיניות.
    2. שליפת רשימת המפתחות עם המזהים שלהם מנקודת הקצה שצוינה של JWKS, או ממטמון פנימי אם נעשה שימוש בנקודת הקצה הזו של JWKS בעבר.
    3. בודקים את הכותרת של JWS/JWT כדי למצוא את מזהה המפתח (kid). אם ה-JWT הנכנס לא כולל מזהה מפתח (kid) בכותרת, אי אפשר למפות את ה-kid למפתח האימות, ו-Apigee יציג שגיאה.
    4. מחפשים במפתחות ה-JWK את מפתח ה-JWK עם מזהה המפתח שצוין בכותרת JWS/JWT. אם לא נמצא מפתח עם מזהה המפתח הזה, מוצגת שגיאה.
    5. בודקים שהאלגוריתם של ה-JWK תואם לאלגוריתם שצוין בהגדרות המדיניות. אם האלגוריתמים לא תואמים, דוחים את האימות ומקפיצים הודעת שגיאה.
    6. משתמשים במפתח הציבורי כדי לאמת את החתימה ב-JWS/JWT. אם האימות נכשל, דוחים את האימות ומפעילים שגיאה.
  • אפשרות 2: בהגדרת המדיניות, מציינים משתנה שמכיל את ה-URI של נקודת הקצה של JWKS ברכיב <PublicKey/JWKS>.

    לדוגמה, במדיניות VerifyJWT:

    <VerifyJWT name="JWT-Verify-RS256">
      <Algorithm>RS256</Algorithm>
      <Source>json.jwt</Source>
      <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
      <PublicKey>
        <JWKS uriRef="variable-containing-a-uri"/>
      </PublicKey>
      . . .
    </VerifyJWT>

    במקרה כזה, Apigee יבצע את אותם השלבים כמו למעלה, אלא ש-Apigee יאחזר את ה-JWKS לא מ-URI שמוגדר בקוד, אלא מה-URI שצוין במשתנה שאליו מתייחס המאפיין uriRef. עדיין חל כאן שימוש במטמון.

  • אפשרות 3: בהגדרת המדיניות, מציינים משתנה שמכיל את נתוני JWKS שמוצפנים בהארדקוד ברכיב <PublicKey/JWKS>.

    לדוגמה, במדיניות VerifyJWT:

    <VerifyJWT name="JWT-Verify-RS256">
      <Algorithm>RS256</Algorithm>
      <Source>json.jwt</Source>
      <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
      <PublicKey>
        <JWKS ref="variable-that-holds-a-jwks"/>
      </PublicKey>
      . . .
    </VerifyJWT>

    במקרה כזה, Apigee יבצע את אותם השלבים שצוינו למעלה, אלא ש-Apigee יאחזר את ה-JWKS לא מ-URI, אלא ממשתנה ההקשר שציינתם במאפיין ref. בדרך כלל, משתנה ההקשר הזה נטען מ-ServiceCallout, מ-KVM או מקובץ מאפיינים שמשויך ל-proxy.

JWKS כמקור מפתחות כשיוצרים JWT מוצפן

כשיוצרים JWT מוצפן באמצעות אלגוריתם אסימטרי (RSA-OAEP-256 או כל אחת מהווריאציות של ECDH-* ‎), משתמשים במפתח הציבורי להצפנה. יש כמה אפשרויות לספק את המפתח למדיניות GenerateJWT:

בדרך כלל מציינים בהגדרת המדיניות את ה-URI של נקודת הקצה של JWKS ברכיב <PublicKey/JWKS>. לדוגמה:

<GenerateJWT name="GJWT-1">
  <Algorithms>
    <Key>RSA-OAEP-256</Key>
    <Content>A128GCM</Content>
  </Algorithms>
  <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
  <PublicKey>
    <JWKS uri='https://www.example.com/.well-known/jwks.json'/>
    <Id ref='variable-containing-desired-keyid'/>
  </PublicKey>
    . . .
</GenerateJWT>

במקרה כזה, Apigee:

  1. הרכבת המטען הייעודי (payload) והכותרת של ה-JWT שלא עברו קידוד, על סמך הגדרות המדיניות.
  2. שליפת רשימת המפתחות עם המזהים שלהם מנקודת הקצה שצוינה של JWKS, או ממטמון פנימי אם נעשה שימוש בנקודת הקצה הזו של JWKS בעבר. בשלב הזה, ה-TTL של המטמון הוא 5 דקות.
  3. מחפשים את מפתח ה-JWK עם מזהה המפתח שצוין ברכיב PublicKey/Id ב-JWKS. אם לא נמצא מפתח עם מזהה המפתח הזה, מוצגת שגיאה.
  4. בודקים שהאלגוריתם של JWK תואם לאלגוריתם שצוין בהגדרות המדיניות. הקפץ הודעת שגיאה אם האלגוריתמים לא תואמים.
  5. יוצרים רצף אקראי שישמש כמפתח להצפנת התוכן.
  6. משתמשים במפתח הציבורי שנבחר כדי להצפין את מפתח ההצפנה של התוכן.
  7. משתמשים במפתח להצפנת התוכן כדי להצפין את המטען הייעודי (payload).
  8. לבסוף, מרכיבים את כל החלקים ל-JWT מוצפן עם מספר סידורי.

אפשרות נוספת היא להשתמש במאפיין uriRef כדי לציין משתנה שמכיל את ה-URI של נקודת קצה של JWKS. לדוגמה:

<GenerateJWT name="GJWT-1">
  <Algorithms>
    <Key>RSA-OAEP-256</Key>
    <Content>A128GCM</Content>
  </Algorithms>
  <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
  <PublicKey>
    <JWKS uriRef='variable-containing-jwks-uri'/>
    <Id ref='variable-containing-desired-keyid'/>
  </PublicKey>
  . . .
</GenerateJWT>

במקרה הזה, Apigee יבצע את אותם השלבים שצוינו למעלה, אלא שאפג'י יאחזר את ה-JWKS מה-URI שצוין במשתנה שאליו מתייחס המאפיין uriRef, במקום מ-URI שמוגדר בהארדקוד. אם נקודת הקצה הזו של JWKS הייתה בשימוש בעבר, מערכת Apigee תקרא את JWKS ממטמון פנימי.