跳到主要内容

jwe-decrypt

API7 企业版 3.10.7 起可用。

jwe-decrypt 插件从请求头读取五段式紧凑 Token,根据 Token 的 kid 选择 Consumer,并使用 AES-256-GCM 解密加密 Payload。在代理请求之前,插件会将明文写入配置的请求头。你可以在 APISIX 路由或服务上启用该插件,并在 Consumer 上配置 32 字节的解密 Secret。

该 Token 采用 JWE 紧凑序列化。插件根据解码后受保护请求头中的 kid 选择 Consumer,并以 direct 加密方式和 A256GCM 解密 Payload。

有两项行为取决于版本。在 API7 企业版 3.10.7 及以后的版本中,编码后的受保护请求头会按 RFC 7516 的规定被用作 AES-GCM 附加认证数据(AAD),因此标准 JWE 库生成的 Token 可以直接使用;不带 AAD 的 Token 同样仍被接受,所以升级前签发的 Token 继续有效。携带的 alg 不是 dir、或者 enc 不是 A256GCM 的 Token 会被直接拒绝,而不是在后续解密时才失败;省略其中任一字段的 Token 仍然会被接受。在不具备这两项行为的版本中,受保护请求头既不会被用作 AAD,也不会被校验:alg 和 enc 会被忽略,标准 RFC 7516 库不能直接互操作,Token 必须严格按照下文所述格式、由固定且可信的生成器生成,并且请求头字段不能被视为已经过认证。

警告

解密后的明文会通过请求头转发。对于敏感明文,不要仅依赖 HTTPS 上游:除非上游启用了校验并提供了自己的 CA 证书,否则上游服务器证书不会被验证;自 API7 企业版 3.10.7 起,该校验对 HTTPS 和 gRPC 上游均生效。请通过能够验证上游服务器身份的代理或服务网格等经过认证和保护的网络路径发送请求,同时限制对上游的访问,并避免记录配置的转发请求头。

示例​

以下示例演示了如何在不同场景下使用 jwe-decrypt 插件。

解密插件 Token 中的数据​

以下示例演示如何解密插件 Token。在 APISIX 外部生成 Token,在 Consumer 上配置匹配的解密密钥,并创建启用 jwe-decrypt 插件的路由来解密 Authorization 请求头。

创建一个启用 jwe-decrypt 的 Consumer 并配置解密密钥:

curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"username": "jack",
"plugins": {
"jwe-decrypt": {
"key": "jack-key",
"secret": "key-length-should-be-32-chars123"
}
}
}'

创建一个启用 jwe-decrypt 的路由以解密 Authorization 头:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "jwe-decrypt-route",
"uri": "/anything/jwe",
"plugins": {
"jwe-decrypt": {
"header": "Authorization",
"forward_header": "Authorization"
}
},
"upstream": {
"type": "roundrobin",
"scheme": "https",
"nodes": {
"httpbin.org:443": 1
}
}
}'

在 APISIX 外部生成 Token:使用 AES-256-GCM 加密 Payload,并使用 Consumer Secret 作为密钥。在 API7 企业版 3.10.7 及以后的版本中,编码后的受保护请求头会被用作 AAD,因此标准 RFC 7516 库生成的 Token 即可被接受;在不具备该行为的版本中,受保护请求头不会被用作 AAD,Token 必须在不带 AAD 的情况下生成。从 3.10.7 起两种形式都能被接受。Token 结构如下:

base64url(header)..base64url(iv).base64url(ciphertext).base64url(tag)

其中,请求头为 {"alg":"dir","enc":"A256GCM","kid":"<consumer-key>"},kid 用于标识 Consumer。在 API7 企业版 3.10.7 及以后的版本中,alg 和 enc 会被校验——取值不是 dir 或 A256GCM 的会被拒绝——并且编码后的请求头会被用作 AAD 进行认证;在不具备该行为的版本中,这两个字段既不会被校验也不会被认证。请为每个 Token 使用唯一且随机生成的 IV;切勿对同一个密钥重复使用 IV。

Payload 和认证标签使用 AES-256-GCM 解密。在 API7 企业版 3.10.7 及以后的版本中,会先带着编码后的受保护请求头作为 AAD 尝试解密,再不带 AAD 尝试一次,因此标准 JWE 库生成的 Token 和不带 AAD 的 Token 都能正常工作。在不具备该行为的版本中,受保护请求头从不作为 AAD 传入,使用标准受保护请求头 AAD 生成的 Token 会失败并报告 failed to decrypt JWE token。

在 Authorization 请求头中携带加密的插件 Token 向路由发送请求。例如,以下 Token 使用上面配置的 Secret 和 Consumer Key jack-key,对 Payload {"uid":10000,"uname":"test"} 进行加密:

curl "http://127.0.0.1:9080/anything/jwe" -H 'Authorization: eyJraWQiOiJqYWNrLWtleSIsImFsZyI6ImRpciIsImVuYyI6IkEyNTZHQ00ifQ..vi29KBCQKcVmPwTT.VToyPMFbq-ZY05MIpntP1N3AmYeq3zELQ0B6iQ.vuTPG2ODc-DjUTjNCzfA2A'

你应该看到类似于以下的响应,其中 Authorization 头显示了 Payload 的明文:

{
"args": {},
"data": "",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Authorization": "{\"uid\":10000,\"uname\":\"test\"}",
"Host": "127.0.0.1",
"User-Agent": "curl/8.1.2",
"X-Amzn-Trace-Id": "Root=1-6510f2c3-1586ec011a22b5094dbe1896",
"X-Forwarded-Host": "127.0.0.1"
},
"json": null,
"method": "GET",
"origin": "127.0.0.1, 119.143.79.94",
"url": "http://127.0.0.1/anything/jwe"
}