מדיניות 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 כדי לציין איך לבצע פענוח קוד של מאמת החתימה.

Error reference

This section describes the fault codes and error messages that are returned and fault variables that are set by Apigee when this policy triggers an error. This information is important to know if you are developing fault rules to handle faults. To learn more, see What you need to know about policy errors and Handling faults.

Runtime errors

These errors can occur when the policy executes.

Fault code HTTP status Occurs when
steps.hmac.UnresolvedVariable 401

This error occurs if a variable specified in the HMAC policy is either:

  • Out of scope (not available in the specific flow where the policy is being executed)

    or

  • Can't be resolved (is not defined)
steps.hmac.HmacVerificationFailed 401 The HMAC verification failed; the verification value provided does not match the calculated value.
steps.hmac.HmacCalculationFailed 401 The policy was unable to calculate the HMAC.
steps.hmac.EmptySecretKey 401 The value of the secret key variable is empty.
steps.hmac.EmptyVerificationValue 401 The variable holding the verification value is emtpy.

Deployment errors

These errors can occur when you deploy a proxy containing this policy.

Error name HTTP status Occurs when
steps.hmac.MissingConfigurationElement 401 This error occurs when a required element or attribute is missing.
steps.hmac.InvalidValueForElement 401 This error occurs if the value specified in the Algorithm element is not one of the following values: SHA-1, SHA-224, SHA-256, SHA-512, or MD-5.
steps.hmac.InvalidSecretInConfig 401 This error occurs if there is a text value explicitly provided for SecretKey.
steps.hmac.InvalidVariableName 401 This error occurs if the SecretKey variable does not contain the private prefix (private.).

Fault variables

These variables are set when a runtime error occurs. For more information, see What you need to know about policy errors.

Variables Where Example
fault.name="fault_name" fault_name is the name of the fault, as listed in the Runtime errors table above. The fault name is the last part of the fault code. fault.name Matches "UnresolvedVariable"
hmac.policy_name.failed The policy sets this variable in the case of a failure. hmac.HMAC-Policy.failed = true

Example error response

For error handling, the best practice is to trap the errorcode part of the error response. Do not rely on the text in the faultstring, because it could change.

Example fault rule

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