הדף הזה רלוונטי ל-Apigee ול-Apigee Hybrid.
לעיון במסמכי התיעוד של
Apigee Edge
מדיניות ה-HMAC מחשבת ומאמתת באופן אופציונלי קוד אימות הודעות מבוסס-גיבוב (HMAC). לפעמים נקרא גם קוד אימות הודעה עם מפתח או גיבוב עם מפתח. ב-HMAC נעשה שימוש בפונקציית גיבוב קריפטוגרפית כמו SHA-1, SHA-224, SHA-256, SHA-384, SHA-512 או MD-5, שמוחלת על 'הודעה', יחד עם מפתח סודי, כדי ליצור חתימה או קוד אימות הודעה על ההודעה הזו. המונח 'הודעה' כאן מתייחס לכל זרם של בייטים. בשימוש רגיל ב-HMAC, שולח ההודעה שולח הודעה ואת ה-HMAC שלה לנמען, והנמען יכול להשתמש ב-HMAC יחד עם סוד לשימוש עם טוקן צרכן כדי לאמת את ההודעה.
המדיניות הזו היא מדיניות רגילה ואפשר לפרוס אותה בכל סוג של סביבה. מידע על סוגי המדיניות והזמינות שלהם בכל סוג סביבה זמין במאמר סוגי מדיניות.
מידע נוסף על HMAC זמין במאמר HMAC: Keyed-Hashing for Message Authentication (rfc2104).
דוגמאות
יצירת HMAC
<HMAC name='HMAC-1'> <Algorithm>SHA256</Algorithm> <!-- the default encoding of the SecretKey is UTF-8 --> <SecretKey encoding='base64' ref='private.secretkey'/> <IgnoreUnresolvedVariables>true|false</IgnoreUnresolvedVariables> <!-- optional --> <!-- The Message element accepts a template, which means the "message" the policy operates on can include fixed and multiple variable parts, including newlines and static functions. Whitespace, such as newlines and space characters, is significant. --> <Message>Fixed Part {a_variable} {timeFormatUTCMs(timeFormatString1,system.timestamp)} {nonce}</Message> <!-- default encoding is base64 --> <Output encoding='base16'>name_of_variable</Output> </HMAC>
אימות HMAC
<HMAC name='HMAC-1'> <Algorithm>SHA256</Algorithm> <!-- the default encoding of the SecretKey is UTF-8 --> <SecretKey encoding='base16' ref='private.secretkey'/> <IgnoreUnresolvedVariables>true|false</IgnoreUnresolvedVariables> <!-- optional --> <!-- The Message element accepts a template. This policy verifies an HMAC on the request content. --> <Message>{request.content}</Message> <!-- VerificationValue is optional. Include it to perform an HMAC check. --> <VerificationValue encoding='base16' ref='expected_hmac_value'/> <!-- default encoding of the output is base64 --> <Output encoding='base16'>name_of_variable</Output> </HMAC>
חישוב החתימה ואימות החתימה מתבצעים בדיוק באותו תהליך. מדיניות ה-HMAC מחשבת HMAC, ויכולה לאמת את החתימה המחושבת מול ערך צפוי. האלמנט האופציונלי VerificationValue
(אם הוא קיים) מכוון את המדיניות לבדוק את הערך המחושב מול ערך ידוע או נתון.
הפניה לרכיב של HMAC
במאמר בנושא הפניות למדיניות מפורטים האלמנטים והמאפיינים של מדיניות HMAC.
מאפיינים שחלים על הרכיב ברמה העליונה
<HMAC name="HMAC" continueOnError="false" enabled="true" async="false">
המאפיינים הבאים משותפים לכל רכיבי ההורה של המדיניות.
| מאפיין | תיאור | ברירת מחדל | נוכחות |
|---|---|---|---|
| name |
השם הפנימי של המדיניות. התווים שאפשר להשתמש בהם בשם מוגבלים ל:A-Z0-9._\-$ %. עם זאת, בממשק המשתמש של Apigee יש הגבלות נוספות, כמו הסרה אוטומטית של תווים שהם לא אלפאנומריים.
אופציונלי, אפשר להשתמש ברכיב |
לא רלוונטי | חובה |
| continueOnError |
מגדירים את הערך false כדי להחזיר שגיאה אם המדיניות נכשלת. זו התנהגות צפויה ברוב המקרים.
הגדרה ל- |
FALSE | אופציונלי |
| מופעל |
כדי לאכוף את המדיניות, צריך להגדיר את הערך true.
מגדירים את הערך |
TRUE | אופציונלי |
| אסינכרוני | המאפיין הזה הוצא משימוש. | FALSE | הוצא משימוש |
<Algorithm>
<Algorithm>algorithm-name</Algorithm>
מציין את אלגוריתם הגיבוב שבו יש להשתמש כשמחשבים את ה-HMAC.
| ברירת מחדל | לא רלוונטי |
| נוכחות | חובה |
| סוג | String |
| ערכים אפשריים | SHA-1, SHA-224, SHA-256, SHA-384,
SHA-512 וגם MD-5
ההגדרה של המדיניות מקבלת שמות של אלגוריתמים בלי להבחין בין אותיות רישיות לאותיות קטנות, ועם או בלי מקף בין האותיות והמספרים. לדוגמה,
|
<DisplayName>
<DisplayName>Policy Display Name</DisplayName>
משתמשים בו בנוסף למאפיין name כדי לתת למדיניות תווית בכלי לעריכת ה-proxy בממשק המשתמש של Apigee, עם שם אחר בשפה טבעית.
| ברירת מחדל | אם לא מציינים את הרכיב הזה, המערכת משתמשת בערך של מאפיין השם של המדיניות. |
| נוכחות | אופציונלי |
| סוג | String |
<Message>
<Message>message_template_here</Message> or <Message ref='variable_here'/>
מציין את מטען ההודעה לחתימה. הקלט של הרכיב הזה תומך בתבניות הודעות (החלפת משתנים) כדי לאפשר הכללה של פריטים נוספים בזמן הריצה, כמו חותמות זמן, ערכי nonce, רשימות של כותרות או מידע אחר. לדוגמה:
<Message>Fixed Part {a_variable} {timeFormatUTCMs(timeFormatString1,system.timestamp)} {nonce} </Message>
תבנית ההודעה יכולה לכלול חלקים קבועים ומשתנים, כולל שורות חדשות ופונקציות סטטיות. לרווחים, כמו שורות חדשות ותווי רווח, יש משמעות.
| ברירת מחדל | לא רלוונטי |
| נוכחות | חובה |
| סוג | String |
| ערכים אפשריים | כל מחרוזת היא ערך טקסט תקין. אם תספקו מאפיין ref, הוא יקבל עדיפות על פני ערך הטקסט. המדיניות בודקת את ערך הטקסט או את המשתנה שאליו יש הפניה כתבנית הודעה. |
<Output>
<Output encoding='encoding_name'>variable_name</Output>
מציין את שם המשתנה שהמדיניות צריכה להגדיר עם ערך ה-HMAC המחושב. הוא גם מציין את הקידוד שישמש לפלט.
| ברירת מחדל |
משתנה הפלט שמוגדר כברירת מחדל הוא ערך ברירת המחדל של מאפיין |
| נוכחות | זה שינוי אופציונלי. אם הרכיב הזה לא קיים, המדיניות מגדירה את משתנה הזרימה hmac.POLICYNAME.output עם ערך בקידוד Base64. |
| סוג | String |
| ערכים אפשריים | לקידוד, הערכים לא תלויי-רישיות. ערך הטקסט של רכיב |
<SecretKey>
<SecretKey encoding='encoding_name' ref='private.secretkey'/>
קובעת את המפתח הסודי שמשמש לחישוב ה-HMAC. המפתח מתקבל מהמשתנה שאליו מתבצעת ההפניה, והוא מפוענח בהתאם לקידוד הספציפי.
| ברירת מחדל |
אין ערך ברירת מחדל למשתנה שאליו יש הפניה;
המאפיין אם לא מצוין מאפיין |
| נוכחות | חובה |
| סוג | String |
| ערכים אפשריים | בפרמטר שימוש במאפיין קידוד מאפשר לציין מפתח שכולל בייטים מחוץ לטווח של תווים שניתנים להדפסה ב-UTF-8. לדוגמה, נניח שהגדרת המדיניות כוללת את הדברים הבאים: <SecretKey encoding='hex' ref='private.encodedsecretkey'/>
נניח ש-
במקרה הזה, הבייטים המרכזיים יפוענחו כך: [53 65 63 72 65 74 31 32 33]
(כל בייט מיוצג בפורמט הקסדצימלי). דוגמה נוספת: אם משתמשים ב- |
<VerificationValue>
<VerificationValue encoding='encoding_name' ref='variable_name'/> or <VerificationValue encoding='encoding_name'>string_value</VerificationValue>
(אופציונלי) מציין את ערך האימות, וגם את הקידוד ששימש לקידוד ערך האימות. המדיניות תשתמש בקידוד הזה כדי לפענח את הערך.
| ברירת מחדל | אין ערך ברירת מחדל לאימות. אם הרכיב קיים אבל המאפיין encoding לא קיים, המדיניות משתמשת בקידוד ברירת מחדל של base64 |
| נוכחות | אופציונלי |
| סוג | String |
| ערכים אפשריים |
הערכים התקפים של מאפיין הקידוד הם: הקידוד של |
<IgnoreUnresolvedVariables>
<IgnoreUnresolvedVariables>true|false</IgnoreUnresolvedVariables>
מגדירים את הערך false אם רוצים שהמדיניות תציג שגיאה כשלא ניתן לפתור משתנה כלשהו שמוגדר במדיניות. הגדרה ל-true תגרום להתייחסות לכל משתנה שלא ניתן לפתור כמחרוזת ריקה (null).
הערך הבוליאני IgnoreUnresolvedVariables משפיע רק על משתנים שההפניה אליהם מופיעה בתבנית ההודעה. אפשר להפנות למשתנה גם ב-SecretKey וגם ב-VerificationValue, אבל צריך להיות אפשר לפתור את שניהם, ולכן ההגדרה ignore לא חלה עליהם.
| ברירת מחדל | לא נכון |
| נוכחות | אופציונלי |
| סוג | בוליאני |
| ערכים אפשריים | true or false |
משתנים בתהליך
המדיניות יכולה להגדיר את המשתנים האלה במהלך ההפעלה.
| משתנה | תיאור | דוגמה |
|---|---|---|
hmac.policy_name.message |
המדיניות מגדירה את המשתנה הזה עם ההודעה האפקטיבית, שהיא התוצאה של הערכת תבנית ההודעה שצוינה ברכיב Message. |
hmac.HMAC-Policy.message = "Hello, World" |
hmac.policy_name.output |
מקבל את התוצאה של חישוב ה-HMAC, כשאלמנט Output לא מציין שם משתנה. |
hmac.HMAC-Policy.output = /yyRjydfP+fBHTwXFgc5AZhLAg2kwCri+e35girrGw4= |
hmac.policy_name.outputencoding |
מקבל את השם של קידוד הפלט. | hmac.HMAC-Policy.outputencoding = base64 |
בעיות נפוצות
ברמה מסוימת, מדיניות ה-HMAC נראית פשוטה: מספקים מפתח והודעה, ומקבלים בתגובה HMAC מחושב. יכול להיות שזה מתסכל להשתמש במדיניות אם מקבלים ערך HMAC לא צפוי לשילוב ידוע של הודעה ומפתח. בסעיף הזה נסביר כמה הערות שימוש שיעזרו לכם לפתור בעיות כאלה.
יש שתי מלכודות נפוצות שגורמות לחוסר התאמה של HMAC במהלך האימות:
הבדלים ברווחים הלבנים בהודעה והבדלים בקידוד ובפענוח.
האחרון חל גם על הרכיב SecretKey וגם על הרכיב Output.
הבדלים ברווחים הלבנים
הבדלים שאולי נראים לא חשובים לבני אדם משפיעים על ערך ה-HMAC של הפלט. לדוגמה,
נניח שיש מפתח סודי שאפשר לייצג אותו כ-Secret123. אחרי פענוח UTF-8, בייטי המפתח יהיו: [53 65 63 72 65 74 31 32 33]. שימוש במפתח הזה כדי לחשב HMAC-SHA256 בהודעה abc יניב את התוצאה a7938720fe5749d31076e6961360364c0cd271443f1b580779932c244293bc94.
הוספת רווח יחיד להודעה, כך שהיא תהיה abc<SPACE>, כאשר <SPACE> מייצג ASCII 32, תניב את התוצאה 274669b2a85d2532da48e2ce3d8e52ee17346d1bcd1a606d87db1934b5ab294b.
באופן דומה, אם ההודעה היא abc<NEWLINE>, כאשר
<NEWLINE> מרמז ASCII 10,
ה-HMAC הוא 0780370844ca07f896066837e8230d3b6a775f678a4ae03e6b5e864c674831f5.
שינויים קלים בהודעה יוצרים ערכי HMAC שונים מאוד. זהו עיצוב מכוון.
זוהי התנהגות מכוונת ורצויה של HMAC.
המסקנה: חשוב לוודא שגוף ההודעה שמשמש לחישוב ה-HMAC המקורי זהה לגוף ההודעה שמשמש לאימות ה-HMAC. אם המאמת של ה-HMAC משנה את מטען ייעודי (payload) של ההודעה בכל דרך שהיא, למשל מוסיף רווח לבן או משנה את הפורמט של הטקסט, ה-HMAC המחושב ישתנה.
צריך לנקוט משנה זהירות כשמשתמשים בתבנית הודעה בהגדרת המדיניות. לדוגמה, בקטע ההגדרה הבא של המדיניות מוצגת בעיה פוטנציאלית:
<HMAC name='HMAC-1'>
...
<!-- the result of this message template will include surrounding whitespace -->
<Message>
{request.content}
</Message>
...
</HMAC>התוצאה של הערכת תבנית ההודעה בתוך רכיב <Message>
תכלול שורות חדשות ורווחים מסביב לתוכן ההודעה. סביר להניח שזה לא מה שהתכוונתם. הגדרה טובה יותר תיראה כך:
<HMAC name='HMAC-1'>
...
<Message>{request.content}</Message>
...
</HMAC>הבדלים בקידוד
פענוחים שונים של אותו חומר מפתח יוצרים מפתחות שונים. נניח שיש מפתח סודי שאפשר לייצג אותו בתור U2VjcmV0S2V5MTIz. אחרי פענוח בקידוד UTF-8, בייטי המפתח כמוצג בקידוד base16 יהיו: [55 32 56 6a 63 6d 56 30 53 32 56 35 4d 54 49 7a].
אחרי פענוח בקידוד Base64, בייטי המפתח יהיו [53 65 63 72 65 74 4b 65 79 31 32 33].
פענוח שונה של חומר המקור יוביל למפתחות שונים, וכתוצאה מכך לערכי HMAC שונים.
המסקנה: חשוב לוודא שחומר המפתח שמשמש לחישוב ה-HMAC המקורי והמפתח שמשמש לאימות ה-HMAC זהים לחלוטין. המשמעות היא כנראה שצריך לוודא שמשתמשים באותו קידוד של המפתח בשני הצדדים. במדיניות HMAC, אפשר להשתמש במאפיין encoding ברכיב SecretKey כדי לציין את קידוד המפתח.
כדאי גם לשקול קידודים בפלט. HMAC-SHA256 בקידוד base16 או הקסדצימלי, שמוצג כ-27f17e11c8ece93844c5eb5e55161d993368628a214f9a51c25d0185e8ea06e2, זהה ל-HMAC-SHA256 בקידוד base64, שמוצג כ-J/F+Ecjs6ThExeteVRYdmTNoYoohT5pRwl0BhejqBuI=.
הן נראות שונות, אבל שתי המחרוזות האלה מייצגות את אותו ערך. מוודאים שנעשה שימוש באותו קידוד כדי לקודד את ה-HMAC שחושב במקור ואת ה-HMAC שמאמת. במדיניות HMAC,
אפשר להשתמש במאפיין encoding ברכיב Output
כדי לציין את קידוד הפלט הרצוי, ובאותו מאפיין ברכיב VerificationValue
כדי לציין איך לפענח את מאמת החשבון.
הפניה לשגיאה
בקטע הזה מתוארים קודי התקלה והודעות השגיאה שמוחזרים, ומשתני התקלה שמוגדרים על ידי Apigee כשמדיניות כזו מפעילה שגיאה. חשוב לדעת את המידע הזה אם אתם מפתחים כללי תקלות לטיפול בתקלות. מידע נוסף על שגיאות שקשורות למדיניות ועל טיפול בשגיאות
שגיאות זמן ריצה
השגיאות האלה יכולות להתרחש כשהמדיניות מופעלת.
| קוד תקלה | סטטוס HTTP | מתרחש כאשר |
|---|---|---|
steps.hmac.UnresolvedVariable |
401 | השגיאה הזו מתרחשת אם משתנה שצוין במדיניות HMAC הוא:
|
steps.hmac.HmacVerificationFailed |
401 | אימות ה-HMAC נכשל. ערך האימות שסופק לא תואם לערך המחושב. |
steps.hmac.HmacCalculationFailed |
401 | המדיניות לא הצליחה לחשב את ה-HMAC. |
steps.hmac.EmptySecretKey |
401 | הערך של משתנה המפתח הסודי ריק. |
steps.hmac.EmptyVerificationValue |
401 | המשתנה שמכיל את ערך האימות ריק. |
שגיאות בהטמעה
השגיאות האלה יכולות להתרחש כשפורסים שרת proxy שמכיל את המדיניות הזו.
| שם השגיאה | סטטוס HTTP | מתרחש כאשר |
|---|---|---|
steps.hmac.MissingConfigurationElement |
401 | השגיאה הזו מתרחשת כשחסר אלמנט או מאפיין נדרש. |
steps.hmac.InvalidValueForElement |
401 | השגיאה הזו מתרחשת אם הערך שצוין ברכיב Algorithm הוא לא אחד מהערכים הבאים: SHA-1, SHA-224, SHA-256, SHA-512 או MD-5. |
steps.hmac.InvalidSecretInConfig |
401 | השגיאה הזו מתרחשת אם יש ערך טקסט שצוין במפורש עבור SecretKey. |
steps.hmac.InvalidVariableName |
401 | השגיאה הזו מתרחשת אם המשתנה SecretKey לא מכיל את הקידומת private (private.). |
משתני תקלות
המשתנים האלה מוגדרים כשמתרחשת שגיאת זמן ריצה. מידע נוסף על שגיאות שקשורות למדיניות
| משתנים | כאשר: | דוגמה |
|---|---|---|
fault.name="fault_name" |
fault_name הוא שם התקלה, כפי שמופיע בטבלה שגיאות בזמן ריצה שלמעלה. שם התקלה הוא החלק האחרון של קוד התקלה. | fault.name Matches "UnresolvedVariable" |
hmac.policy_name.failed |
המדיניות מגדירה את המשתנה הזה במקרה של כשל. | hmac.HMAC-Policy.failed = true |
דוגמה לתגובת שגיאה
לצורך טיפול בשגיאות, מומלץ ללכוד את החלק errorcode בתגובת השגיאה. אל תסתמכו על הטקסט ב-faultstring, כי הוא עשוי להשתנות.
דוגמה לכלל שגיאה
<FaultRules>
<FaultRule name="HMAC Policy Errors">
<Step>
<Name>AM-Unauthorized</Name>
<Condition>(fault.name Matches "HmacVerificationFailed")</Condition>
</Step>
<Condition>hmac.HMAC-1.failed = true</Condition>
</FaultRule>
</FaultRules>