hmac-auth插件需要和 Consumer 一起使用,API 的使用者必须将密匙添加到请求头中以验证其请求,下面介绍它的主要用法
参数
- algorithm 算法 默认hmac-sha256 ["hmac-sha1", "hmac-sha256", "hmac-sha512"],客户端请求头X-HMAC-ALGORITHM=hmac-sha256
- clock_skew 签名允许的时间偏移(以秒为单位)
- access_key Consumer 的 access_key 必须是唯一的,客户端请求时在请求头添加X-HMAC-ACCESS-KEY=access_key值
- signed_headers 要在加密计算中使用的 headers 列表,客户端请求头X-HMAC-SIGNED-HEADERS
- X-HMAC-SIGNATURE 客户端请求头中的签名
消费者配置
- 添加hmac-auth插件,配置access_key,类似于app_id
- 这个消费者有两个能力,除了hmac-auth以外,还有key-auth的能力,即简单的认证方式
签名生成的过程
接下来,我们将以下述请求为例,为你介绍签名生成公式的具体计算过程:
curl -i http://127.0.0.1:9080/index.html?name=james&age=36 \
-H "X-HMAC-SIGNED-HEADERS: User-Agent;x-custom-a" \
-H "x-custom-a: test" \
-H "User-Agent: curl/7.29.0"
- 上文请求默认的 HTTP Method 是 GET,得到 signing_string 为:
"GET"
- 请求的 URI 是 /index.html,根据 HTTP Method + \n + HTTP URI 得到 signing_string 为:
"GET
/index.html"
- URL 中的 query 项是 name=james&age=36,假设 encode_uri_params 为 false,根据 canonical_query_string 的算法,重点是对 key 进行字典排序,得到 age=36&name=james;根据 HTTP Method + \n + HTTP URI + \n + canonical_query_string 得到 signing_string 为:
"GET
/index.html
age=36&name=james"
- access_key 是 user-key,根据 HTTP Method + \n + HTTP URI + \n + canonical_query_string + \n + access_key 得到 signing_string 为:
"GET
/index.html
age=36&name=james
user-key"
- Date 是指
GMT
格式的日期,不能缺少,形如 Tue, 19 Jan 2021 11:33:20 GMT, 根据 HTTP Method + \n + HTTP URI + \n + canonical_query_string + \n + access_key + \n + Date 得到 signing_string 为:
"GET
/index.html
age=36&name=james
user-key
Tue, 19 Jan 2021 11:33:20 GMT"
因为人家apisix服务端lua插件源码,使用的是这种GMT格式,所以咱们使用者也需要跟人家保持一致,事实上,我更倾向于使用时间戳,没有日期格式和时区的问题
- signed_headers_string 用来制定参与到签名的 headers,在上面示例中包括 User-Agent: curl/7.29.0 和 x-custom-a: test。
根据 HTTP Method + \n + HTTP URI + \n + canonical_query_string + \n + access_key + \n + Date + \n + signed_headers_string + \n,得到完整的 signing_string 为:
"GET
/index.html
age=36&name=james
user-key
Tue, 19 Jan 2021 11:33:20 GMT
User-Agent:curl/7.29.0
x-custom-a:test
"
Body请求体校验
当 validate_request_body 设置为 true 时,插件将计算请求 body 的 hmac-sha 值,并与请求 headers 中的 X-HMAC-DIGEST 的值进行校验。
X-HMAC-DIGEST: base64(hmac-sha())
X-HMAC-DIGEST: base64(hmac-sha(<body>))
如果没有请求 body,你可以将 X-HMAC-DIGEST 的值设置为空字符串的 HMAC-SHA。
注意:
当开启 body 校验时,为了计算请求 body 的 hmac-sha 值,该插件会把 body 加载到内存中,在请求 body 较大的情况下,可能会造成较高的内存消耗。
为了避免这种情况,你可以通过设置 max_req_body(默认值是 512KB)配置项来配置最大允许的 body 大小,body 超过此大小的请求会被拒绝。
测试插件
假设当前请求为:
curl -i http://127.0.0.1:9080/index.html?name=james&age=36 \
-H "X-HMAC-SIGNED-HEADERS: User-Agent;x-custom-a" \
-H "x-custom-a: test" \
-H "User-Agent: curl/7.29.0"
通过以下 Python 代码为上述请求生成签名 SIGNATURE:
import base64
import hashlib
import hmacsecret = bytes('my-secret-key', 'utf-8')
message = bytes("""GET
/index.html
age=36&name=james
user-key
Tue, 19 Jan 2021 11:33:20 GMT
User-Agent:curl/7.29.0
x-custom-a:test
""", 'utf-8')hash = hmac.new(secret, message, hashlib.sha256)# to lowercase base64
print(base64.b64encode(hash.digest()))
Type | Hash |
---|---|
SIGNATURE | 8XV1GB7Tq23OJcoz6wjqTs4ZLxr9DiLoY4PxzScWGYg= |
你也可以参考 Generating HMAC signatures 了解如何使用不同的编程语言生成签名。
签名生成后,你可以通过以下示例使用生成的签名发起请求:
curl -i "http://127.0.0.1:9080/index.html?name=james&age=36" \
-H "X-HMAC-SIGNATURE: 8XV1GB7Tq23OJcoz6wjqTs4ZLxr9DiLoY4PxzScWGYg=" \
-H "X-HMAC-ALGORITHM: hmac-sha256" \
-H "X-HMAC-ACCESS-KEY: user-key" \
-H "Date: Tue, 19 Jan 2021 11:33:20 GMT" \
-H "X-HMAC-SIGNED-HEADERS: User-Agent;x-custom-a" \
-H "x-custom-a: test" \
-H "User-Agent: curl/7.29.0"HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Date: Tue, 19 Jan 2021 11:33:20 GMT
Server: APISIX/2.2
......
你也可以将签名放到请求头 Authorization 字段中:
curl http://127.0.0.1:9080/index.html \
-H 'Authorization: hmac-auth-v1# + ACCESS_KEY + # + base64_encode(SIGNATURE) + # + ALGORITHM + # + DATE + # + SIGNED_HEADERS' -i
postman测试结果