אתם צופים במסמכי התיעוד של Apigee Edge.
כדאי לעיין במסמכי התיעוד של Apigee X. מידע
במאמר הזה מוסבר על JWT (JSON Web Token) ו-JWS (JSON Web Signature) ועל מדיניות JWS/JWT של Apigee שעשויה לעניין מפתחי פרוקסי של Apigee.
מבוא
גם JWS וגם JWT משמשים בדרך כלל לשיתוף טענות או הצהרות בין אפליקציות מקושרות. כללי המדיניות של JWS/JWT מאפשרים ל-API proxies ב-Edge:
- יוצרים JWT חתום או JWS.
- אימות של JWT חתום או JWS חתום וההצהרות ב-JWS או ב-JWT.
- פענוח של JWT חתום או של JWS בלי לאמת את החתימה.
בשני המקרים האחרונים, המדיניות גם מגדירה משתנים שמאפשרים למדיניות נוספת, או לשירותי הקצה העורפי עצמם, לבדוק את הטענות שאומתו ולקבל החלטות על סמך הטענות האלה.
כשמשתמשים במדיניות Verify JWS/JWT (אימות JWS/JWT), בקשת JWS/JWT לא תקינה תידחה ותגרום לשגיאה. באופן דומה, כשמשתמשים במדיניות Decode JWS/JWT, JWS/JWT פגום יגרום לתנאי שגיאה.
סרטונים
כדאי לצפות בסרטון הקצר הזה כדי לקבל מבוא מהיר ל-JWT. הסרטון הזה מתמקד ביצירת JWT, אבל הרבה מהמושגים רלוונטיים גם ל-JWS.
אפשר לצפות בסרטון הקצר הזה כדי לקבל מידע נוסף על המבנה של JWT.
תרחישים לדוגמה
אתם יכולים להשתמש במדיניות JWS/JWT כדי:
- יוצרים JWS או JWT חדשים בצד ה-proxy או בצד נקודת הקצה של היעד ב-Edge proxy. לדוגמה, אפשר ליצור תהליך בקשת פרוקסי שיוצר JWS או JWT ומחזיר אותו ללקוח. לחלופין, אפשר לעצב שרת proxy כך שהוא ייצור JWS/JWT בתהליך הבקשה של היעד, ויצרף אותו לבקשה שנשלחת ליעד. הטענות האלה יהיו זמינות כדי לאפשר לשירותי קצה עורפיים להחיל עיבוד אבטחה נוסף.
- אימות ומיצוי של טענות נכוֹנוּת (assertions) מ-JWS/JWT שהתקבלו מבקשות לקוח נכנסות, מתגובות של שירות היעד, מתגובות של מדיניות Service Callout או ממקורות אחרים. Edge יאמת את החתימה ב-JWS/JWT, בין אם ה-JWS/JWT נוצר על ידי צד שלישי או על ידי Edge עצמו, באמצעות אלגוריתמים של RSA או HMAC.
- פענוח של JWS או JWT. הפענוח הכי שימושי כשמשתמשים בו יחד עם המדיניות Verify JWS/JWT, כשצריך לדעת את הערך של טענה (JWT) או כותרת (JWS/JWT) מתוך ה-JWS/JWT לפני שמאמתים את ה-JWS/JWT.
החלקים של JWS/JWT
JWS או JWT חתום מקודד מידע בשלושה חלקים שמופרדים באמצעות נקודות: הכותרת, המטען הייעודי (payload) והחתימה:
header.payload.signature
- המדיניות Generate JWS/JWT יוצרת את כל שלושת החלקים.
- המדיניות Verify JWS/JWT בודקת את כל שלושת החלקים.
- המדיניות Decode JWS/JWT בודקת רק את הכותרת ואת המטען הייעודי (payload).
בנוסף, JWS תומך בפורמט מנותק שבו המטען הייעודי מושמט מ-JWS:
header..signature
ב-JWS מנותק, המטען הייעודי (payload) נשלח בנפרד מה-JWS. משתמשים ברכיב
<DetachedContent> של מדיניות Verify JWS כדי לציין את מטען ה-JWS הגולמי שלא עבר קידוד.
לאחר מכן, מדיניות האימות של JWS מאמתת את ה-JWS באמצעות הכותרת והחתימה ב-JWS והמטען הייעודי (payload) שצוין ברכיב <DetachedContent>.
מידע נוסף על אסימונים, על הקידוד שלהם ועל החתימה שלהם זמין במאמרים הבאים:
- JWT: IETF RFC7519
- JWS: IETF RFC7515
ההבדלים בין JWS לבין JWT
אפשר להשתמש ב-JWT או ב-JWS כדי לשתף הצהרות או טענות בין אפליקציות מקושרות. ההבדל העיקרי בין שתי השיטות הוא הייצוג של מטען הייעודי (payload):
- JWT
- המטען הייעודי (payload) הוא תמיד אובייקט JSON
- המטען הייעודי (payload) תמיד מצורף ל-JWT
- הכותרת
typשל הטוקן תמיד מוגדרת לערךJWT
- JWS
- המטען הייעודי יכול להיות מיוצג בכל פורמט, כמו אובייקט JSON, זרם בייטים, זרם אוקטטים ועוד
- המטען הייעודי (payload) לא חייב להיות מצורף ל-JWS
מכיוון שפורמט ה-JWT תמיד משתמש באובייקט JSON כדי לייצג את המטען הייעודי (payload), למדיניות Edge Generate JWT ולמדיניות Verify JWT יש תמיכה מובנית בטיפול בשמות נפוצים של הצהרות רשומות, כמו aud, iss, sub ועוד. כלומר, אפשר להשתמש ברכיבים של מדיניות Generate JWT כדי להגדיר את הטענות האלה במטען הייעודי (payload), וברכיבים של מדיניות Verify JWT כדי לאמת את הערכים שלהן. מידע נוסף זמין בקטע Registered Claim Names במפרט JWT.
בנוסף לתמיכה בשמות מסוימים של הצהרות רשומות, מדיניות Generate JWT תומכת ישירות בהוספת הצהרות עם שמות שרירותיים ל-JWT. כל טענה היא זוג פשוט של שם/ערך, כאשר הערך יכול להיות מסוג מספר, ערך בוליאני, מחרוזת, מפה או מערך.
מכיוון ש-JWS יכול להשתמש בכל ייצוג נתונים עבור המטען הייעודי (payload), אי אפשר להוסיף הצהרות למטען הייעודי. מדיניות Generate JWS תומכת בהוספת טענות עם שמות שרירותיים לכותרת של ה-JWS. בנוסף, מדיניות JWS תומכת במטען ייעודי (payload) מנותק, שבו מטען ייעודי מושמט מ-JWS. מטען נפרד מאפשר לשלוח את ה-JWS ואת המטען בנפרד, והוא נדרש על ידי כמה תקני אבטחה.
מניעת הזרקת תבניות כשמשתמשים ב-JWS וב-JWT
כדי למנוע חשיפה לא מורשית של נתונים, צריך לפעול לפי ההנחיות הבאות כשמשתמשים במדיניות GenerateJWT או GenerateJWS:
- הימנעות מהפניות ישירות לקלט של משתמשים: אסור להשתמש בקלט לא מהימן (כמו
request.queryparam.*אוrequest.header.*) ישירות במאפייןrefשתומך בתבניות. - ניקוי קלט: אם אתם חייבים להשתמש בנתונים חיצוניים בהצהרת JWT/JWS, קודם צריך להשתמש במדיניות AssignMessage כדי להסיר מהקלט סוגריים מסולסלים (
{ }) או תווים אחרים של תבנית לפני שמתייחסים אליו. - שימוש בהצהרות מפורשות למחרוזות: בהצהרות פשוטות של מחרוזות, לא משתמשים ב-
type="map". שימוש בערך ברירת המחדלtype="string"מונע יצירת תבנית משתמעת של הערך שאליו מתבצעת ההפניה. - שימו לב לחוסר העקביות בהתנהגות בין מדיניות האימות לבין מדיניות היצירה: מדיניות יצירה של JWS ו-JWT מתנהגת באופן שונה ממדיניות אימות בכל הנוגע לשימוש בתבניות.
מידע על אלגוריתמים של חתימות
מדיניות האימות והיצירה של JWS/JWT תומכת באלגוריתמים RSA, RSASSA-PSS, ECDSA ו-HMAC, באמצעות סכומי ביקורת של SHA2 בעוצמת סיביות של 256, 384 או 512. מדיניות הפענוח של JWS/JWT פועלת ללא קשר לאלגוריתם ששימש לחתימה על JWS/JWT.
אלגוריתם HMAC
אלגוריתם ה-HMAC מסתמך על סוד לשימוש עם טוקן צרכן, שנקרא המפתח הסודי, כדי ליצור את החתימה (שנקראת גם חתימה על JWS או JWT) וכדי לאמת את החתימה.
אורך מפתח הסוד המינימלי תלוי בחוזק הביטים של האלגוריתם:
- HS256: אורך מפתח מינימלי של 32 בייט
- HS386: אורך מפתח מינימלי של 48 בייט
- HS512: אורך המפתח המינימלי הוא 64 בייטים
אלגוריתם RSA
אלגוריתם RSA משתמש בזוג מפתחות ציבורי/פרטי לחתימה הקריפטוגרפית. בחתימות RSA, הצד החותם משתמש במפתח פרטי של RSA כדי לחתום על JWS/JWT, והצד המאמת משתמש במפתח ציבורי תואם של RSA כדי לאמת את החתימה על JWS/JWT. אין דרישות גודל לגבי המפתחות.
אלגוריתם RSASSA-PSS
אלגוריתם RSASSA-PSS הוא עדכון של אלגוריתם RSA. בדומה ל-RSS, RSASSA-PSS משתמש בזוג מפתחות RSA ציבורי/פרטי לחתימה הקריפטוגרפית. הפורמט של המפתח זהה לפורמט של RSS. הגורם החותם משתמש במפתח פרטי כדי לחתום על JWS/JWT, והגורם המאמת משתמש במפתח ציבורי תואם כדי לאמת את החתימה על JWS/JWT. אין דרישות גודל לגבי המפתחות.
אלגוריתם 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) |
אלגוריתמים להצפנת מפתחות
מדיניות JWS/JWT תומכת בכל אלגוריתמי הצפנת המפתחות שנתמכים על ידי OpenSSL.
שימוש ב-JSON Web Key Set (JWKS) כדי לאמת JWS או JWT
כשמאמתים JWS או JWT חתומים, צריך לספק את המפתח הציבורי שמשויך למפתח הפרטי ששימש לחתימה על האסימון. יש שתי אפשרויות לספק את המפתח הציבורי למדיניות האימות של JWS/JWT:
- להשתמש בערך הממשי של המפתח הציבורי (בדרך כלל מסופק במשתנה של זרימת נתונים), או
- שימוש במפתח ציבורי שעטוף ב-JWKS.
מידע על JWKS
קובץ JWKS הוא מבנה JSON שמייצג קבוצה של מפתחות אינטרנט מסוג JSON (JWK). JWK הוא מבנה נתונים בפורמט JSON שמייצג מפתח קריפטוגרפי. JWK ו-JWKS מתוארים ב-RFC7517. דוגמאות ל-JKWS מופיעות בנספח א'. דוגמאות לערכות מפתחות אינטרנט בפורמט JSON
המבנה של JWKS
ב-RFC7517 מפורטים רכיבי המפתח של JWKS לכל סוג מפתח, כמו RSA או EC. לדוגמה, בהתאם לסוג המפתח, הפרמטרים האלה יכולים לכלול:
- kty – סוג המפתח, כמו RSA או EC.
- kid (מזהה המפתח) – יכול להיות כל ערך שרירותי (ללא כפילויות בתוך קבוצת מפתחות). אם ל-JWT הנכנס יש מזהה מפתח שקיים בקבוצת ה-JWKS, המדיניות תשתמש במפתח הציבורי הנכון כדי לאמת את החתימה של ה-JWS/JWT.
הנה דוגמאות לרכיבים אופציונליים ולערכים שלהם:
- alg – אלגוריתם המפתח. הוא צריך להיות זהה לאלגוריתם החתימה ב-JWS או ב-JWT.
- use – אם התג הזה מופיע, הערך שלו חייב להיות sig.
ה-JWKS הבא כולל את הרכיבים והערכים הנדרשים, והוא יהיה תקף ב-Edge (מתוך https://www.googleapis.com/oauth2/v3/certs):
{
"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",
}
]
}תכנון שרת ה-proxy לשימוש ב-JWKS
כשמקבלים JWS/JWT מגורם מנפיק, לעיתים קרובות הגורם המנפיק מוסיף מזהה מפתח (או kid) לכותרת של ה-JWS/JWT. המפתח מציין לנמען של JWS או JWT איך למצוא את המפתח הציבורי או הסודי שנדרש כדי לאמת את החתימה על ה-JWS או ה-JWT החתומים.
לדוגמה, נניח שגורם מנפיק חותם על JWT באמצעות מפתח פרטי. הערך של 'מזהה המפתח' מציין את המפתח הציבורי התואם שמשמש לאימות ה-JWT. רשימת המפתחות הציבוריים זמינה בדרך כלל בנקודת קצה מוכרת, למשל: https://www.googleapis.com/oauth2/v3/certs.
זו הרצף הבסיסי שדפדפן Edge (או כל פלטפורמה שפועלת עם JWKS) צריך לבצע כדי לעבוד עם JWS/JWT שיש לו JWKS:
- בודקים את הכותרת של JWS/JWT כדי למצוא את מזהה המפתח (kid).
- בודקים את הכותרת של JWS/JWT כדי למצוא את אלגוריתם החתימה (alg), כמו RS256.
- אחזור רשימת המפתחות והמזהים מ-JWKS של נקודת הקצה המוכרת עבור מנפיק נתון.
- מחפשים ברשימת המפתחות את המפתח הציבורי עם מזהה המפתח שצוין בכותרת JWS/JWT, ועם האלגוריתם התואם, אם המפתח JWKS מציין את האלגוריתם.
- משתמשים במפתח הציבורי הזה כדי לאמת את החתימה ב-JWS או ב-JWT.
כמפתחים של proxy ל-API של Edge, אתם צריכים לבצע את הפעולות הבאות כדי לבצע אימות של JWS/JWT:
- אחזור רשימת המפתחות והמזהים מנקודת הקצה המוכרת של מנפיק נתון. אפשר להשתמש במדיניות Service Callout בשלב הזה.
- במדיניות Verify JWS/JWT, מציינים את המיקום של JWS/JWT ברכיב
<Source>ואת מטען ה-JWKS ברכיב<PublicKey/JWKS>. לדוגמה, במדיניות VerifyJWT:<VerifyJWT name="JWT-Verify-RS256"> <Algorithm>RS256</Algorithm> <Source>json.jwt</Source> <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables> <PublicKey> <JWKS ref="public.jwks"/> </PublicKey> <Subject>apigee-seattle-hatrack-montage</Subject> <Issuer>urn://apigee-edge-JWT-policy-test</Issuer> <Audience>urn://c60511c0-12a2-473c-80fd-42528eb65a6a</Audience> <AdditionalClaims> <Claim name="show">And now for something completely different.</Claim> </AdditionalClaims> </VerifyJWT>
המדיניות Verify JWT עושה את כל השאר:
- אם לא נמצא מפתח עם מזהה מפתח שזהה למזהה המפתח (kid) שצוין ב-JWT, המדיניות Verify JWT (אימות JWT) תחזיר שגיאה ולא תאמת את ה-JWT.
- אם ב-JWT הנכנס לא מופיע מזהה מפתח (kid) בכותרת, אי אפשר לבצע את המיפוי הזה של keyid-to-verification-key.
בתור מעצב הפרוקסי, אתם אחראים לקביעת המפתח לשימוש. במקרים מסוימים, יכול להיות שזה יהיה מפתח קבוע שמוטמע בקוד.