סקירה כללית של מדיניות 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. לדוגמה, אפשר ליצור תהליך בקשת פרוקסי שיוצר JWS או JWT ומחזיר אותו ללקוח. לחלופין, אפשר לעצב שרת proxy כך שהוא ייצור JWS/JWT בתהליך הבקשה של היעד, ויצרף אותו לבקשה שנשלחת ליעד. אז ה-JWS/JWT והטענות שלו יהיו זמינים כדי לאפשר לשירותי קצה עורפי להחיל עיבוד אבטחה נוסף.
  • אימות ומיצוי של טענות נכוֹנוּת (assertions) מ-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 תומך בפורמט מנותק שבו המטען מושמט מ-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, זרם בייטים, זרם אוקטט ועוד.
    • לא צריך לצרף את המטען הייעודי (payload) ל-JWS.
    • הכותרת והמטען הייעודי (payload) תמיד חתומים. ‫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 ואת המטען בנפרד. שימוש במטען ייעודי מנותק יכול להיות יעיל יותר מבחינת נפח, במיוחד במטענים ייעודיים גדולים, והוא נדרש על ידי כמה תקני אבטחה.

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

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

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

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

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

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

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

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

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

במקרה של 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

קבוצת האלגוריתמים של Elliptic Curve Digital Signature Algorithm (אלגוריתם חתימה דיגיטלית של עקום אליפטי, 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 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. מחפשים במפתחות JWKS את מפתח 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 יבצע את אותם השלבים כמו למעלה, אבל הוא יאחזר את ה-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 יבצע את אותם השלבים שצוינו למעלה, אבל במקום כתובת URI שמוגדרת בקוד, Apigee יאחזר את ה-JWKS מכתובת ה-URI שצוינה במשתנה שאליו מתייחס המאפיין uriRef. אם נקודת הקצה הזו של JWKS הייתה בשימוש בעבר, מערכת Apigee תקרא את JWKS ממטמון פנימי.