hmac-auth

该插件需要和 Consumer 一起使用,API 的使用者必须将密匙添加到请求头中以验证其请求。

属性

首先,我们需要在 Consumer 中启用该插件,如下所示:

你也可以通过 的 Web 界面完成操作。

然后就可以在 Route 或 Service 中启用插件,如下所示:

  1. curl http://127.0.0.1:9080/apisix/admin/routes/1 \
  2. -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
  3. {
  4. "uri": "/index.html",
  5. "plugins": {
  6. "hmac-auth": {}
  7. },
  8. "upstream": {
  9. "type": "roundrobin",
  10. "nodes": {
  11. "127.0.0.1:1980": 1
  12. }
  13. }
  14. }'

测试插件

需注意,在使用 hmac-auth 插件时,会涉及到签名。签名的计算公式为 signature = HMAC-SHAx-HEX(secret_key, signing_string)

为了生成签名需要两个参数:secret_keysigning_string。其中 secret_key 由对应 Consumer 配置,signing_string 的计算公式为 signing_string = HTTP Method + \n + HTTP URI + \n + canonical_query_string + \n + access_key + \n + Date + \n + signed_headers_string。如果 signing_string 中的某一项不存在,则需要使用一个空字符串代替:

  • HTTP Method:指 HTTP 协议中定义的 GET、PUT、POST 等请求方法,必须使用全大写的形式。
  • HTTP URI:HTTP URI。必须以 “/” 开头,“/” 表示空路径。
  • Date:请求头中的日期(GMT 格式)。
  • canonical_query_string:对 URL 中的 query(query 即 URL 中 ? 后面的 key1=valve1&key2=valve2 字符串)进行编码后的结果。
  • signed_headers_string:从请求头中获取客户端指定的字段,并按顺序拼接字符串的结果。
  1. 提取 URL 中的 query 项。

  2. 如果 encode_uri_paramtrue 时:

    • 当该项有 key 时,转换公式为 url_encode(key) + "="
    • 当该项同时有 keyvalue 时,转换公式为 url_encode(key) + "=" + url_encode(value) 。此处 value 可以是空字符串。
    • 将每一项转换后,以 key 按照字典顺序(ASCII 码由小到大)排序,并使用 & 符号连接起来,生成相应的 canonical_query_string
  3. 如果 encode_uri_param 为 时:

    • 当该项只有 key 时,转换公式为 key + "="
    • 当该项同时有 keyvalue 时,转换公式为 key + "=" + value 。此处 value 可以是空字符串。

生成 signed_headers_string 的算法如下:

  1. 从请求头中获取指定的 headers 加入计算中。
  2. 从请求头中按顺序取出 SIGNED_HEADERS 指定的 headers,并按顺序用 name:value 方式拼接起来,拼接完后就生成了 signed_headers_string
  1. HeaderKey1 + ":" + HeaderValue1 + "\n"\+
  2. HeaderKey2 + ":" + HeaderValue2 + "\n"\+
  3. ...
  4. HeaderKeyN + ":" + HeaderValueN + "\n"

以下示例为你展示了签名字符串的拼接:

  1. curl -i http://127.0.0.1:9080/index.html?name=james&age=36 \
  2. -H "X-HMAC-SIGNED-HEADERS: User-Agent;x-custom-a" \
  3. -H "x-custom-a: test" \
  4. -H "User-Agent: curl/7.29.0"

根据上述算法生成的 signing_string 为:

  1. "GET
  2. /index.html
  3. age=36&name=james
  4. user-key
  5. Tue, 19 Jan 2021 11:33:20 GMT
  6. User-Agent:curl/7.29.0
  7. x-custom-a:test
  8. "

最后一个请求头也需要 + \n

以下示例是通过使用 Python 来生成签名 SIGNATURE

TypeHash
SIGNATURE8XV1GB7Tq23OJcoz6wjqTs4ZLxr9DiLoY4PxzScWGYg=

您也可以参考 Generating HMAC signatures 了解如何为不同的编程语言生成签名。

  1. X-HMAC-DIGEST: base64(hmac-sha(<body>))

如果没有请求 body,你可以将 X-HMAC-DIGEST 的值设置为空字符串的 HMAC-SHA。

note

当开启 body 校验时,为了计算请求 body 的 hmac-sha 值,插件会把 body 加载到内存中,在请求 body 较大的情况下,可能会造成较高的内存消耗。为了避免这种情况,你可以通过设置 max_req_body(默认值是 512KB)配置项来配置最大允许的 body 大小,body 超过此大小的请求会被拒绝。

你可以通过以下示例使用生成的签名发起请求:

  1. curl -i "http://127.0.0.1:9080/index.html?name=james&age=36" \
  2. -H "X-HMAC-SIGNATURE: 8XV1GB7Tq23OJcoz6wjqTs4ZLxr9DiLoY4PxzScWGYg=" \
  3. -H "X-HMAC-ALGORITHM: hmac-sha256" \
  4. -H "X-HMAC-ACCESS-KEY: user-key" \
  5. -H "Date: Tue, 19 Jan 2021 11:33:20 GMT" \
  6. -H "X-HMAC-SIGNED-HEADERS: User-Agent;x-custom-a" \
  7. -H "x-custom-a: test" \
  8. -H "User-Agent: curl/7.29.0"
  1. HTTP/1.1 200 OK
  2. Content-Type: text/html; charset=utf-8
  3. Transfer-Encoding: chunked
  4. Connection: keep-alive
  5. Server: APISIX/2.2
  6. ......

签名可以放到请求头 Authorization 字段中:

  1. curl http://127.0.0.1:9080/index.html \
  2. -H 'Authorization: hmac-auth-v1# + ACCESS_KEY + # + base64_encode(SIGNATURE) + # + ALGORITHM + # + DATE + # + SIGNED_HEADERS' -i

也可以将签名单独放在另一个请求头中:

  1. curl http://127.0.0.1:9080/index.html \
  2. -H 'X-HMAC-SIGNATURE: base64_encode(SIGNATURE)' \
  3. -H 'X-HMAC-ALGORITHM: ALGORITHM' \
  4. -H 'X-HMAC-ACCESS-KEY: ACCESS_KEY' \
  5. -H 'X-HMAC-SIGNED-HEADERS: SIGNED_HEADERS' -i
  1. HTTP/1.1 200 OK
  2. Content-Type: text/html
  3. Content-Length: 13175
  4. ...
  5. Accept-Ranges: bytes
  6. <!DOCTYPE html>
  7. <html lang="cn">
hmac-auth - 图2note
  1. ACCESS_KEY、SIGNATURE、ALGORITHM、DATE、SIGNED_HEADERS 分别代表对应的变量。
  2. SIGNED_HEADERS 为客户端指定的加入加密计算的 headers。若存在多个 headers 需以 “;” 分割,例如:x-custom-header-a;x-custom-header-b
  3. SIGNATURE 需要使用 base64 进行加密:base64_encode(SIGNATURE)

除了配置签名外,你还可以在配置文件(conf/config.yaml)中的plugin_attr 配置项下,添加 hmac-auth 插件的属性来自定义参数 header 名称。如下所示:

conf/config.yaml

  1. plugin_attr:
  2. hmac-auth:
  3. signature_key: X-APISIX-HMAC-SIGNATURE
  4. algorithm_key: X-APISIX-HMAC-ALGORITHM
  5. date_key: X-APISIX-DATE
  6. access_key: X-APISIX-HMAC-ACCESS-KEY
  7. signed_headers_key: X-APISIX-HMAC-SIGNED-HEADERS
  8. body_digest_key: X-APISIX-HMAC-BODY-DIGEST

配置完成后,你可以使用自定义的 header 发起请求。

  1. curl http://127.0.0.1:9080/index.html \
  2. -H 'X-APISIX-HMAC-SIGNATURE: base64_encode(SIGNATURE)' \
  3. -H 'X-APISIX-HMAC-ALGORITHM: ALGORITHM' \
  4. -H 'X-APISIX-DATE: DATE' \
  5. -H 'X-APISIX-HMAC-ACCESS-KEY: ACCESS_KEY' \
  6. -H 'X-APISIX-HMAC-SIGNED-HEADERS: SIGNED_HEADERS' \
  7. -H 'X-APISIX-HMAC-BODY-DIGEST: BODY_DIGEST' -i

禁用插件

  1. curl http://127.0.0.1:9080/apisix/admin/routes/1 \
  2. -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
  3. {
  4. "uri": "/index.html",
  5. "plugins": {},
  6. "upstream": {
  7. "type": "roundrobin",
  8. "nodes": {
  9. "127.0.0.1:1980": 1
  10. }
  11. }