a6-plugin-hmac-auth
概览
hmac-auth 插件使用 HMAC(Hash-based Message
Authentication Code)签名对请求进行认证。客户端会基于
请求方法、路径、日期以及可选请求头/请求体计算 HMAC 签名,然后将其放入
Authorization 请求头中。Apache APISIX会在服务端重新计算签名并校验
其是否匹配。这种方式无需在线路上传输密钥,
即可验证请求完整性。
适用场景
- 请求完整性校验(防止 API 调用被篡改)
- 适用于双方共享密钥的服务间认证
- 需要校验请求体完整性的 API
- Token 或密码不应出现在请求中的环境
插件配置参考(路由/服务)
| 字段 | 类型 | 是否必填 | 默认值 | 说明 |
|---|---|---|---|---|
allowed_algorithms | array | 否 | ["hmac-sha1","hmac-sha256","hmac-sha512"] | 允许使用的 HMAC 算法 |
clock_skew | integer | 否 | 300 | 客户端与服务端之间允许的最大时间差,单位秒 |
signed_headers | array | 否 | — | HMAC 签名中要求包含的额外请求头 |
validate_request_body | boolean | 否 | false | 通过 SHA-256 摘要校验请求体完整性 |
hide_credentials | boolean | 否 | false | 转发到上游前 移除 Authorization 请求头 |
anonymous_consumer | string | 否 | — | 未认证请求使用的消费者用户名 |
realm | string | 否 | "hmac" | WWW-Authenticate 响应头中的 Realm |
消费者凭证参考
| 字段 | 类型 | 是否必填 | 说明 |
|---|---|---|---|
key_id | string | 是 | 消费者的唯一标识符 |
secret_key | string | 是 | 用于 HMAC 计算的 Secret,存储到 etcd 时自动加密 |
分步操作:在路由上启用 hmac-auth
1. 创建消费者
a6 consumer create -f - <<'EOF'
{
"username": "alice"
}
EOF
2. 添加 hmac-auth 凭证
curl "$(a6 context current -o json | jq -r .server)/apisix/admin/consumers/alice/credentials" \
-X PUT \
-H "X-API-KEY: $(a6 context current -o json | jq -r .api_key)" \
-d '{
"id": "cred-alice-hmac",
"plugins": {
"hmac-auth": {
"key_id": "alice-key",
"secret_key": "alice-secret-key-value"
}
}
}'
3. 创建启用 hmac-auth 的路由
a6 route create -f - <<'EOF'
{
"id": "hmac-protected",
"uri": "/api/*",
"plugins": {
"hmac-auth": {}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"backend:8080": 1
}
}
}
EOF
4. 生成签名并测试
HMAC 签名遵循 HTTP Signatures 草案。
Python 示例:
import hmac, hashlib, base64
from datetime import datetime, timezone
key_id = "alice-key"
secret_key = b"alice-secret-key-value"
method = "GET"
path = "/api/users"
algorithm = "hmac-sha256"
gmt_time = datetime.now(timezone.utc).strftime('%a, %d %b %Y %H:%M:%S GMT')
signing_string = f"{key_id}\n{method} {path}\ndate: {gmt_time}\n"
signature = base64.b64encode(
hmac.new(secret_key, signing_string.encode(), hashlib.sha256).digest()
).decode()
# Use these headers in request:
# Date: {gmt_time}
# Authorization: Signature keyId="{key_id}",algorithm="{algorithm}",
# headers="@request-target date",signature="{signature}"
curl 示例:
curl -i http://127.0.0.1:9080/api/users \
-H "Date: $(date -u +'%a, %d %b %Y %H:%M:%S GMT')" \
-H 'Authorization: Signature keyId="alice-key",algorithm="hmac-sha256",headers="@request-target date",signature="<computed_signature>"'
Authorization 请求头格式
Signature keyId="{key_id}",algorithm="{algorithm}",headers="{signed_headers}",signature="{signature}"
| 组件 | 说明 |
|---|---|
keyId | 消费者的 key_id 值 |
algorithm | hmac-sha1、hmac-sha256、hmac-sha512 之一 |
headers | 以空格分隔的列表:@request-target date [additional...] |
signature | Base64 编码的 HMAC 签名 |
签名字符串构造
签名字符串以换行分隔:
{key_id}\n
{METHOD} {path}\n
date: {Date header value}\n
{additional-header}: {value}\n
- 第一行:
key_id - 第二行:HTTP 方法 + 空格 + 请求路径
- 后续行:小写请求头名称及其值
- 每一行都以
\n结束
常见模式
限制为指定算法
{
"plugins": {
"hmac-auth": {
"allowed_algorithms": ["hmac-sha256", "hmac-sha512"]
}
}
}
增大时钟偏差容忍度
{
"plugins": {
"hmac-auth": {
"clock_skew": 600
}
}
}
允许最多 10 分钟的时间差。
校验请求体
{
"plugins": {
"hmac-auth": {
"validate_request_body": true
}
}
}
客户端必须包含 Digest: SHA-256={base64_sha256_of_body} 请求头。Apache APISIX
会重新计算请求体摘要;如果不匹配,则拒绝请求。