本页面适用于 Apigee 和 Apigee Hybrid。
查看 Apigee Edge 文档。
此政策计算并选择性地验证基于哈希的消息身份验证代码 (HMAC)。HMAC 有时称为“密钥消息身份验证代码”或“密钥哈希”,它使用诸如 SHA-1、SHA-224、SHA-256、SHA-384、SHA-512 或 MD-5之类的加密哈希函数,与密钥一起应用于“消息”,以在该消息上生成签名或消息身份验证代码。此处的“消息”一词指任何字节流。在典型的 HMAC 用法中,消息的发送者向接收者发送消息及其 HMAC,而接收者可以使用 HMAC 以及共享密钥对消息进行身份验证。
此政策为标准政策,可部署到任何环境类型。如需了解政策类型以及在每种环境类型中的可用性,请参阅政策类型。
如需详细了解 HMAC,请参阅 HMAC:用于消息身份验证的键控哈希技术 (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">
以下属性是所有政策的父级元素都具有的属性。
属性 | 说明 | 默认 | Presence |
---|---|---|---|
name |
政策的内部名称。您可以在名称中使用的字符仅限于 A-Z0-9._\-$ % 。但是,Apigee 界面会实施其他限制,例如自动移除非字母数字字符。(可选)使用 |
不适用 | 必填 |
continueOnError |
设置为 false 可在政策失败时返回错误。对于大多数政策来说,这一行为符合预期。设置为 |
false | 可选 |
已启用 | 设置为 true 可实施政策。设置为 |
true | 可选 |
async | 此属性已弃用。 | false | 已弃用 |
<Algorithm>
<Algorithm>algorithm-name</Algorithm>
指定在计算 HMAC 时使用的哈希算法。
默认 | 不适用 |
Presence | 必填 |
类型 | 字符串 |
有效值 | SHA-1 、SHA-224 、SHA-256 、SHA-384 、SHA-512 和 MD-5
政策配置接受不区分大小写的算法名称,字母与数字之间可以包含短划线,也可以不包含短划线。例如, |
<DisplayName>
<DisplayName>Policy Display Name</DisplayName>
除了用于名称属性之外,还可以用于在 Apigee 界面代理编辑器中给政策添加不同的自然语言名称标签。
默认 | 如果省略此元素,则会使用政策的名称属性的值。 |
Presence | 可选 |
类型 | 字符串 |
<Message>
<Message>message_template_here</Message> or <Message ref='variable_here'/>
此元素指定要签名的消息载荷。此元素的输入支持消息模板(变量替换),允许在运行时添加其他项,例如时间戳、Nonce、标头列表或其他信息。例如:
<Message>Fixed Part {a_variable} {timeFormatUTCMs(timeFormatString1,system.timestamp)} {nonce} </Message>
消息模板可以包含固定和可变部分,包括换行符和静态函数。空白(例如换行符和空格字符)很重要。
默认 | 不适用 |
Presence | 必填 |
类型 | 字符串 |
有效值 | 任何字符串对文本值都有效。如果您提供 ref 特性,它将优先于文本值。该政策将文本值或引用的变量作为消息模板进行评估。 |
<Output>
<Output encoding='encoding_name'>variable_name</Output>
此元素指定政策应根据计算出的 HMAC 值设置的变量的名称。还指定要用于输出的编码。
默认 |
默认输出变量为 |
Presence | 可选。如果该元素不存在,则政策会设置流变量 hmac.POLICYNAME.output ,并采用 base64 编码值。 |
类型 | 字符串 |
有效值 | 对于编码,有效值包括 值不区分大小写;
|
<SecretKey>
<SecretKey encoding='encoding_name' ref='private.secretkey'/>
指定用于计算 HMAC 的密钥。该键从引用的变量中获取,并根据特定编码进行解码。
默认 |
引用的变量没有默认值; 如果缺少 |
Presence | 必填 |
类型 | 字符串 |
有效值 | 对于 使用编码特性,您可以指定一个包含 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 。 |
Presence | 可选 |
类型 | 字符串 |
有效值 |
编码特性的有效值包括
|
<IgnoreUnresolvedVariables>
<IgnoreUnresolvedVariables>true|false</IgnoreUnresolvedVariables>
如果您希望在政策中指定的任何引用的变量无法解析时政策抛出错误,则设置为 false
。设置为 true
可将任何无法解析的变量视为空字符串 (null)。
IgnoreUnresolvedVariables 布尔值仅会影响消息模板引用的变量。虽然 SecretKey
和 VerificationValue
可以引用变量,但这两者都需要可解析,因此 ignore
设置不适用于这些元素。
默认 | False |
Presence | 可选 |
类型 | 布尔值 |
有效值 | true 或 false |
流变量
该政策可以在执行期间设置这些变量。
变量 | 说明 | 示例 |
---|---|---|
hmac.policy_name.message |
该政策根据有效的消息以及 Message 元素中指定的消息模板的评估结果设置此变量。 |
hmac.HMAC-Policy.message = "Hello, World" |
hmac.policy_name.output |
当 Output 元素未指定变量名称时,获取 HMAC 计算的结果。 |
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]
。使用该密钥计算消息 abc
上的 HMAC-SHA256 会导致 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 政策中,您可以使用 SecretKey
元素上的 encoding
属性来指定密钥编码。
此外,请考虑输出的编码。以 base16 或十六进制编码表示的 27f17e11c8ece93844c5eb5e55161d993368628a214f9a51c25d0185e8ea06e2
的 HMAC-SHA256 与以 base64 编码形式表示的 J/F+Ecjs6ThExeteVRYdmTNoYoohT5pRwl0BhejqBuI=
的 HMAC-SHA256 相同。它们看起来有所不同,但这两个字符串代表相同的值。确保使用相同的编码对最初计算的 HMAC 和验证 HMAC 进行编码。在 HMAC 政策中,您可以使用 Output
元素上的 encoding
属性指定所需的输出编码,并使用 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 | 包含验证值的变量为空。 |
部署错误
在您部署包含此政策的代理时,可能会发生这些错误。
错误名称 | HTTP 状态 | 发生的条件 |
---|---|---|
steps.hmac.MissingConfigurationElement |
401 | 当缺少必需的元素或特性时,就会出现此错误。 |
steps.hmac.InvalidValueForElement |
401 | 如果算法元素中指定的值不是以下值之一,则会出现此错误: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>