מדיניות HMAC

מדיניות רגילה

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

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

מדיניות HMAC מחשבת קוד אימות הודעות (HMAC) מבוסס-גיבוב (hash) ומאמתת אותו (אופציונלית). לפעמים נקרא 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 יש הגבלות נוספות, כמו הסרה אוטומטית של תווים שהם לא אלפאנומריים.

אופציונלי. אפשר להשתמש ברכיב <DisplayName> כדי להוסיף תווית למדיניות בכלי לעריכת ה-proxy בממשק המשתמש של Apigee, עם שם אחר בשפה טבעית.

לא רלוונטי חובה
continueOnError מגדירים את הערך false כדי להחזיר שגיאה אם המדיניות נכשלת. זו התנהגות צפויה ברוב המדיניות.

הגדרה ל-true מאפשרת להמשיך את הביצוע של התהליך גם אחרי שמדיניות נכשלת. מידע נוסף:

FALSE אופציונלי
מופעל מגדירים את המדיניות למצב true כדי לאכוף אותה.

מגדירים את הערך false כדי להשבית את המדיניות. המדיניות לא תיאכף גם אם היא תישאר מצורפת לזרימה.

TRUE אופציונלי
אסינכרוני המאפיין הזה הוצא משימוש. FALSE הוצא משימוש

<Algorithm>

<Algorithm>algorithm-name</Algorithm>

מציין את אלגוריתם הגיבוב שבו יש להשתמש כשמחשבים את ה-HMAC.

ברירת מחדל לא רלוונטי
נוכחות חובה
סוג String
ערכים אפשריים SHA-1, SHA-224, SHA-256, SHA-384, SHA-512 וגם MD-5

הגדרת המדיניות מקבלת שמות של אלגוריתמים בלי להבחין בין אותיות רישיות לאותיות קטנות, ועם או בלי מקף בין האותיות והמספרים. לדוגמה, SHA256 ו-SHA-256 ו-sha256 שווים זה לזה.

<DisplayName>

<DisplayName>Policy Display Name</DisplayName>

משתמשים בו בנוסף למאפיין name כדי לתת למדיניות תווית בכלי לעריכת proxy בממשק המשתמש של Apigee, עם שם אחר בשפה טבעית.

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

<Message>

<Message>message_template_here</Message>
or
<Message ref='variable_here'/>

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

<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.

ערך ברירת המחדל של מאפיין encoding הוא base64.

נוכחות זה שינוי אופציונלי. אם הרכיב הזה לא קיים, המדיניות מגדירה את משתנה הזרימה hmac.POLICYNAME.output עם ערך בקידוד Base64.
סוג String
ערכים אפשריים

לקידוד, hex, base16, base64, base64url.

הערכים לא תלויי-רישיות. למשל, hex ו-base16 הם מילים נרדפות.

ערך הטקסט של רכיב Output יכול להיות כל שם חוקי של משתנה זרימה.

<SecretKey>

<SecretKey encoding='encoding_name' ref='private.secretkey'/>

קובעת את המפתח הסודי שמשמש לחישוב ה-HMAC. המפתח מתקבל מהמשתנה שאליו מתבצעת ההפניה, והוא מפוענח בהתאם לקידוד הספציפי.

ברירת מחדל

אין ערך ברירת מחדל למשתנה שאליו יש הפניה; המאפיין ref הוא חובה.

אם לא מצוין מאפיין encoding, המדיניות מפענחת כברירת מחדל את מחרוזת המפתח הסודי באמצעות UTF-8 כדי לקבל את בייטי המפתח.

נוכחות חובה
סוג String
ערכים אפשריים

במאפיין encoding, הערכים התקפים הם hex,‏ base16,‏ base64 ו-utf8. ברירת המחדל היא UTF8. הערכים לא תלויי-רישיות, והמקפים לא משמעותיים. ‫Base16 זהה ל-base-16 ול-bAse16. ‫Base16 ו-Hex הן מילים נרדפות.

שימוש במאפיין קידוד מאפשר לציין מפתח שכולל בייטים מחוץ לטווח של תווים שניתנים להדפסה ב-UTF-8. לדוגמה, נניח שהגדרת המדיניות כוללת את הדברים הבאים:

 <SecretKey encoding='hex' ref='private.encodedsecretkey'/>

נניח שהמשתנה private.encodedsecretkey מכיל את המחרוזת 536563726574313233.

במקרה הזה, הבייטים המרכזיים יפוענחו כך: [53 65 63 72 65 74 31 32 33] (כל בייט מיוצג בפורמט הקסדצימלי). דוגמה נוספת: אם משתמשים ב-encoding='base64', ואם private.encodedsecretkey מכיל את המחרוזת U2VjcmV0MTIz, התוצאה תהיה אותו מערך של בייטים עבור המפתח. אם לא מציינים מאפיין קידוד, או אם מציינים מאפיין קידוד עם הערך UTF8, ערך המחרוזת Secret123 יניב את אותה קבוצת בייטים. בדוגמה הזו מוצגות שלוש דרכים שונות לייצוג של אותו מקש.

<VerificationValue>

<VerificationValue encoding='encoding_name' ref='variable_name'/>
or
<VerificationValue encoding='encoding_name'>string_value</VerificationValue>

(אופציונלי) מציין את ערך האימות, וגם את הקידוד ששימש לקידוד ערך האימות. המדיניות תשתמש בקידוד הזה כדי לפענח את הערך.

ברירת מחדל אין ערך אימות שמוגדר כברירת מחדל. אם הרכיב קיים אבל המאפיין encoding לא מופיע, המדיניות משתמשת בקידוד ברירת מחדל של base64
נוכחות אופציונלי
סוג String
ערכים אפשריים

הערכים התקפים של מאפיין הקידוד הם: hex, ‏ base16,‏ base64, ‏ base64url. הערכים לא תלויי-רישיות. hex ו-base16 הם מילים נרדפות.

הקידוד של VerificationValue לא צריך להיות זהה לקידוד שמשמש לרכיב Output.

<IgnoreUnresolvedVariables>

<IgnoreUnresolvedVariables>true|false</IgnoreUnresolvedVariables>

מגדירים את הערך false אם רוצים שהמדיניות תקפיץ הודעת שגיאה כשלא ניתן לפתור משתנה כלשהו שמוגדר במדיניות. הגדרה ל-true תגרום להתייחסות לכל משתנה שלא ניתן לפתור כמחרוזת ריקה (null).

הערך הבוליאני IgnoreUnresolvedVariables משפיע רק על משתנים שההפניה אליהם מופיעה בתבנית ההודעה. אפשר להפנות למשתנה גם ב-SecretKey וגם ב-VerificationValue, אבל צריך להיות אפשר לפתור את שניהם, ולכן ההגדרה ignore לא חלה עליהם.

ברירת מחדל לא נכון
נוכחות אופציונלי
סוג בוליאני
ערכים אפשריים נכון או לא נכון

משתני Flow

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

משתנה תיאור דוגמה
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, תגרום ל-HMAC-SHA256 של 274669b2a85d2532da48e2ce3d8e52ee17346d1bcd1a606d87db1934b5ab294b.

באופן דומה, אם ההודעה היא abc<NEWLINE>, כאשר <NEWLINE> מרמז ASCII 10, ה-HMAC הוא 0780370844ca07f896066837e8230d3b6a775f678a4ae03e6b5e864c674831f5. שינויים קלים בהודעה יוצרים ערכי HMAC שונים מאוד. זה קורה בכוונה. זוהי התנהגות מכוונת ורצויה של HMAC.

המסקנה: חשוב לוודא שגוף ההודעה שמשמש לחישוב ה-HMAC המקורי וגוף ההודעה שמשמש לאימות ה-HMAC זהים לחלוטין. אם המאמת של HMAC משנה את מטען ההודעה בכל דרך שהיא, על ידי הוספת רווח לבן או עיצוב מחדש של הטקסט, ה-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.). private

משתני תקלות

המשתנים האלה מוגדרים כשמתרחשת שגיאת זמן ריצה. מידע נוסף על שגיאות שקשורות למדיניות

משתנים כאשר: דוגמה
fault.name="fault_name" fault_name הוא שם התקלה, כפי שמופיע בטבלה Runtime errors שלמעלה. שם התקלה הוא החלק האחרון של קוד התקלה. 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>