This is an automated email from the ASF dual-hosted git repository.

kayx23 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git


The following commit(s) were added to refs/heads/master by this push:
     new 64d831f4f3 docs(plugin): sign the Digest header in the hmac-auth body 
validation example (#14159)
64d831f4f3 is described below

commit 64d831f4f389ad652eb9b180fd4fd5f9c794b5b0
Author: Abhinav <[email protected]>
AuthorDate: Fri Nov 13 09:05:40 2026 +0530

    docs(plugin): sign the Digest header in the hmac-auth body validation 
example (#14159)
    
    * docs(plugin): sign the Digest header in the hmac-auth body validation 
example
    
    The hmac-sig-digest-header-gen.py example sent a Digest header that was 
never covered by the HMAC signature. The example now signs digest in headers 
@request-target date digest, matching the validate_request_body configuration 
it accompanies.
    
    * docs(plugin): require digest to be signed in body-validation examples
    
    Per review: sign-digest examples now list digest in signed_headers, the 
successful response and 401 example are consistent, and the 401 example uses a 
tampered body.
    
    * docs(hmac-auth): use fresh digest signatures in examples
    
    * docs(hmac-auth): align Chinese body validation example
    
    ---------
    
    Co-authored-by: kayx23 <[email protected]>
---
 docs/en/latest/plugins/hmac-auth.md | 95 +++++++++++++++++++-----------------
 docs/zh/latest/plugins/hmac-auth.md | 96 ++++++++++++++++++++-----------------
 2 files changed, 103 insertions(+), 88 deletions(-)

diff --git a/docs/en/latest/plugins/hmac-auth.md 
b/docs/en/latest/plugins/hmac-auth.md
index da2d9486c4..90879885f3 100644
--- a/docs/en/latest/plugins/hmac-auth.md
+++ b/docs/en/latest/plugins/hmac-auth.md
@@ -668,7 +668,8 @@ curl "http://127.0.0.1:9180/apisix/admin/routes"; -X PUT \
     "methods": ["POST"],
     "plugins": {
       "hmac-auth": {
-        "validate_request_body": true
+        "validate_request_body": true,
+        "signed_headers": ["date", "digest"]
       }
     },
     "upstream": {
@@ -706,6 +707,9 @@ services:
         plugins:
           hmac-auth:
             validate_request_body: true
+            signed_headers:
+              - date
+              - digest
     upstream:
       type: roundrobin
       nodes:
@@ -771,6 +775,9 @@ spec:
         _meta:
           disable: false
         validate_request_body: true
+        signed_headers:
+          - date
+          - digest
 ---
 apiVersion: gateway.networking.k8s.io/v1
 kind: HTTPRoute
@@ -853,6 +860,9 @@ spec:
         enable: true
         config:
           validate_request_body: true
+          signed_headers:
+            - date
+            - digest
 ```
 
 Apply the configuration to your cluster:
@@ -890,6 +900,10 @@ body = '{"name": "world"}'          # example request body
 # skew to prolong the validity within the advised security boundary
 gmt_time = datetime.now(timezone.utc).strftime('%a, %d %b %Y %H:%M:%S GMT')
 
+# create the SHA-256 digest of the request body and include it in the signing 
string
+body_digest = hashlib.sha256(body.encode('utf-8')).digest()
+digest_header = "SHA-256=" + base64.b64encode(body_digest).decode('utf-8')
+
 # construct the signing string (ordered)
 # the date and any subsequent custom headers should be lowercased and 
separated by a
 # single space character, i.e. `<key>:<space><value>`
@@ -898,51 +912,39 @@ signing_string = (
     f"{key_id}\n"
     f"{request_method} {request_path}\n"
     f"date: {gmt_time}\n"
+    f"digest: {digest_header}\n"
 )
 
 # create signature
 signature = hmac.new(secret_key, signing_string.encode('utf-8'), 
hashlib.sha256).digest()
 signature_base64 = base64.b64encode(signature).decode('utf-8')
 
-# create the SHA-256 digest of the request body and base64 encode it
-body_digest = hashlib.sha256(body.encode('utf-8')).digest()
-body_digest_base64 = base64.b64encode(body_digest).decode('utf-8')
-
-# construct the request headers
-headers = {
-    "Date": gmt_time,
-    "Digest": f"SHA-256={body_digest_base64}",
-    "Authorization": (
-        f'Signature keyId="{key_id}",algorithm="hmac-sha256",'
-        f'headers="@request-target date",'
-        f'signature="{signature_base64}"'
-    )
-}
-
-# print headers
-print(headers)
-```
-
-Run the script:
-
-```shell
-python3 hmac-sig-digest-header-gen.py
-```
-
-You should see the request headers printed:
+# construct the Authorization header
+authorization = (
+    f'Signature keyId="{key_id}",algorithm="hmac-sha256",'
+    f'headers="@request-target date digest",'
+    f'signature="{signature_base64}"'
+)
 
-```text
-{'Date': 'Fri, 06 Sep 2024 09:16:16 GMT', 'Digest': 
'SHA-256=78qzJuLwSpZ8HacsTdFCQJWxzPMOf8bYctRk2ySLpS8=', 'Authorization': 
'Signature keyId="john-key",algorithm="hmac-sha256",headers="@request-target 
date",signature="rjS6NxOBKmzS8CZL05uLiAfE16hXdIpMD/L/HukOTYE="'}
+# print one value per line for the verification command to read
+print(gmt_time)
+print(digest_header)
+print(authorization)
 ```
 
-Using the headers generated, send a request to the Route:
+Generate fresh values and pass them directly to the request:
 
 ```shell
-curl "http://127.0.0.1:9080/post"; -X POST \
-  -H "Date: Fri, 06 Sep 2024 09:16:16 GMT" \
-  -H "Digest: SHA-256=78qzJuLwSpZ8HacsTdFCQJWxzPMOf8bYctRk2ySLpS8=" \
-  -H 'Authorization: Signature 
keyId="john-key",algorithm="hmac-sha256",headers="@request-target 
date",signature="rjS6NxOBKmzS8CZL05uLiAfE16hXdIpMD/L/HukOTYE="' \
-  -d '{"name": "world"}'
+python3 hmac-sig-digest-header-gen.py | {
+  IFS= read -r HMAC_DATE
+  IFS= read -r HMAC_DIGEST
+  IFS= read -r HMAC_AUTHORIZATION
+  curl "http://127.0.0.1:9080/post"; -X POST \
+    -H "Date: ${HMAC_DATE}" \
+    -H "Digest: ${HMAC_DIGEST}" \
+    -H "Authorization: ${HMAC_AUTHORIZATION}" \
+    -d '{"name": "world"}'
+}
 ```
 
 You should see an `HTTP/1.1 200 OK` response similar to the following:
@@ -957,11 +959,11 @@ You should see an `HTTP/1.1 200 OK` response similar to 
the following:
   },
   "headers": {
     "Accept": "*/*",
-    "Authorization": "Signature 
keyId=\"john-key\",algorithm=\"hmac-sha256\",headers=\"@request-target 
date\",signature=\"rjS6NxOBKmzS8CZL05uLiAfE16hXdIpMD/L/HukOTYE=\"",
+    "Authorization": "<generated Authorization header>",
     "Content-Length": "17",
     "Content-Type": "application/x-www-form-urlencoded",
-    "Date": "Fri, 06 Sep 2024 09:16:16 GMT",
-    "Digest": "SHA-256=78qzJuLwSpZ8HacsTdFCQJWxzPMOf8bYctRk2ySLpS8=",
+    "Date": "<generated Date header>",
+    "Digest": "<generated Digest header>",
     "Host": "127.0.0.1",
     "User-Agent": "curl/8.6.0",
     "X-Amzn-Trace-Id": "Root=1-66d978c3-49f929ad5237da5340bbbeb4",
@@ -975,14 +977,19 @@ You should see an `HTTP/1.1 200 OK` response similar to 
the following:
 }
 ```
 
-If you send a request without the digest or with an invalid digest:
+If you send the same signed headers with a different body, the `Digest` header 
no longer matches:
 
 ```shell
-curl "http://127.0.0.1:9080/post"; -X POST \
-  -H "Date: Fri, 06 Sep 2024 09:16:16 GMT" \
-  -H "Digest: SHA-256=78qzJuLwSpZ8HacsTdFCQJWxzPMOf8bYctRk2ySLpS8=" \
-  -H 'Authorization: Signature 
keyId="john-key",algorithm="hmac-sha256",headers="@request-target 
date",signature="rjS6NxOBKmzS8CZL05uLiAfE16hXdIpMD/L/HukOTYE="' \
-  -d '{"name": "world"}'
+python3 hmac-sig-digest-header-gen.py | {
+  IFS= read -r HMAC_DATE
+  IFS= read -r HMAC_DIGEST
+  IFS= read -r HMAC_AUTHORIZATION
+  curl "http://127.0.0.1:9080/post"; -X POST \
+    -H "Date: ${HMAC_DATE}" \
+    -H "Digest: ${HMAC_DIGEST}" \
+    -H "Authorization: ${HMAC_AUTHORIZATION}" \
+    -d '{"name": "tampered"}'
+}
 ```
 
 You should see an `HTTP/1.1 401 Unauthorized` response with the following 
message:
diff --git a/docs/zh/latest/plugins/hmac-auth.md 
b/docs/zh/latest/plugins/hmac-auth.md
index 7082219796..ed9bd593a5 100644
--- a/docs/zh/latest/plugins/hmac-auth.md
+++ b/docs/zh/latest/plugins/hmac-auth.md
@@ -618,7 +618,7 @@ curl -X GET "http://127.0.0.1:9080/get"; \
 
 ### 启用请求正文验证
 
-以下示例演示如何启用请求正文验证以确保请求正文的完整性。
+以下示例演示如何启用请求正文验证,并将正文摘要纳入 HMAC 签名,以确保请求正文的完整性。
 
 <Tabs
 groupId="api"
@@ -668,7 +668,8 @@ curl "http://127.0.0.1:9180/apisix/admin/routes"; -X PUT \
     "methods": ["POST"],
     "plugins": {
       "hmac-auth": {
-        "validate_request_body": true
+        "validate_request_body": true,
+        "signed_headers": ["date", "digest"]
       }
     },
     "upstream": {
@@ -706,6 +707,9 @@ services:
         plugins:
           hmac-auth:
             validate_request_body: true
+            signed_headers:
+              - date
+              - digest
     upstream:
       type: roundrobin
       nodes:
@@ -771,6 +775,9 @@ spec:
         _meta:
           disable: false
         validate_request_body: true
+        signed_headers:
+          - date
+          - digest
 ---
 apiVersion: gateway.networking.k8s.io/v1
 kind: HTTPRoute
@@ -853,6 +860,9 @@ spec:
         enable: true
         config:
           validate_request_body: true
+          signed_headers:
+            - date
+            - digest
 ```
 
 将配置应用到集群:
@@ -890,6 +900,10 @@ body = '{"name": "world"}'          # example request body
 # skew to prolong the validity within the advised security boundary
 gmt_time = datetime.now(timezone.utc).strftime('%a, %d %b %Y %H:%M:%S GMT')
 
+# create the SHA-256 digest of the request body and include it in the signing 
string
+body_digest = hashlib.sha256(body.encode('utf-8')).digest()
+digest_header = "SHA-256=" + base64.b64encode(body_digest).decode('utf-8')
+
 # construct the signing string (ordered)
 # the date and any subsequent custom headers should be lowercased and 
separated by a
 # single space character, i.e. `<key>:<space><value>`
@@ -898,51 +912,39 @@ signing_string = (
     f"{key_id}\n"
     f"{request_method} {request_path}\n"
     f"date: {gmt_time}\n"
+    f"digest: {digest_header}\n"
 )
 
 # create signature
 signature = hmac.new(secret_key, signing_string.encode('utf-8'), 
hashlib.sha256).digest()
 signature_base64 = base64.b64encode(signature).decode('utf-8')
 
-# create the SHA-256 digest of the request body and base64 encode it
-body_digest = hashlib.sha256(body.encode('utf-8')).digest()
-body_digest_base64 = base64.b64encode(body_digest).decode('utf-8')
-
-# construct the request headers
-headers = {
-    "Date": gmt_time,
-    "Digest": f"SHA-256={body_digest_base64}",
-    "Authorization": (
-        f'Signature keyId="{key_id}",algorithm="hmac-sha256",'
-        f'headers="@request-target date",'
-        f'signature="{signature_base64}"'
-    )
-}
-
-# print headers
-print(headers)
-```
-
-运行脚本:
-
-```shell
-python3 hmac-sig-digest-header-gen.py
-```
-
-您应该看到打印的请求标头:
+# construct the Authorization header
+authorization = (
+    f'Signature keyId="{key_id}",algorithm="hmac-sha256",'
+    f'headers="@request-target date digest",'
+    f'signature="{signature_base64}"'
+)
 
-```text
-{'Date': 'Fri, 06 Sep 2024 09:16:16 GMT', 'Digest': 
'SHA-256=78qzJuLwSpZ8HacsTdFCQJWxzPMOf8bYctRk2ySLpS8=', 'Authorization': 
'Signature keyId="john-key",algorithm="hmac-sha256",headers="@request-target 
date",signature="rjS6NxOBKmzS8CZL05uLiAfE16hXdIpMD/L/HukOTYE="'}
+# print one value per line for the verification command to read
+print(gmt_time)
+print(digest_header)
+print(authorization)
 ```
 
-使用生成的标头,向 Route 发送请求:
+生成新值,并将其直接传入请求:
 
 ```shell
-curl "http://127.0.0.1:9080/post"; -X POST \
-  -H "Date: Fri, 06 Sep 2024 09:16:16 GMT" \
-  -H "Digest: SHA-256=78qzJuLwSpZ8HacsTdFCQJWxzPMOf8bYctRk2ySLpS8=" \
-  -H 'Authorization: Signature 
keyId="john-key",algorithm="hmac-sha256",headers="@request-target 
date",signature="rjS6NxOBKmzS8CZL05uLiAfE16hXdIpMD/L/HukOTYE="' \
-  -d '{"name": "world"}'
+python3 hmac-sig-digest-header-gen.py | {
+  IFS= read -r HMAC_DATE
+  IFS= read -r HMAC_DIGEST
+  IFS= read -r HMAC_AUTHORIZATION
+  curl "http://127.0.0.1:9080/post"; -X POST \
+    -H "Date: ${HMAC_DATE}" \
+    -H "Digest: ${HMAC_DIGEST}" \
+    -H "Authorization: ${HMAC_AUTHORIZATION}" \
+    -d '{"name": "world"}'
+}
 ```
 
 您应该会看到类似于以下内容的 `HTTP/1.1 200 OK` 响应:
@@ -957,11 +959,11 @@ curl "http://127.0.0.1:9080/post"; -X POST \
   },
   "headers": {
     "Accept": "*/*",
-    "Authorization": "Signature 
keyId=\"john-key\",algorithm=\"hmac-sha256\",headers=\"@request-target 
date\",signature=\"rjS6NxOBKmzS8CZL05uLiAfE16hXdIpMD/L/HukOTYE=\"",
+    "Authorization": "<generated Authorization header>",
     "Content-Length": "17",
     "Content-Type": "application/x-www-form-urlencoded",
-    "Date": "Fri, 06 Sep 2024 09:16:16 GMT",
-    "Digest": "SHA-256=78qzJuLwSpZ8HacsTdFCQJWxzPMOf8bYctRk2ySLpS8=",
+    "Date": "<generated Date header>",
+    "Digest": "<generated Digest header>",
     "Host": "127.0.0.1",
     "User-Agent": "curl/8.6.0",
     "X-Amzn-Trace-Id": "Root=1-66d978c3-49f929ad5237da5340bbbeb4",
@@ -975,13 +977,19 @@ curl "http://127.0.0.1:9080/post"; -X POST \
 }
 ```
 
-如果您发送的请求没有 digest 或 digest 无效:
+如果使用相同的签名标头发送不同的请求正文,`Digest` 标头将不再与正文匹配:
 
 ```shell
-curl "http://127.0.0.1:9080/post"; -X POST \
-  -H "Date: Fri, 06 Sep 2024 09:16:16 GMT" \
-  -H 'Authorization: Signature 
keyId="john-key",algorithm="hmac-sha256",headers="@request-target 
date",signature="rjS6NxOBKmzS8CZL05uLiAfE16hXdIpMD/L/HukOTYE="' \
-  -d '{"name": "world"}'
+python3 hmac-sig-digest-header-gen.py | {
+  IFS= read -r HMAC_DATE
+  IFS= read -r HMAC_DIGEST
+  IFS= read -r HMAC_AUTHORIZATION
+  curl "http://127.0.0.1:9080/post"; -X POST \
+    -H "Date: ${HMAC_DATE}" \
+    -H "Digest: ${HMAC_DIGEST}" \
+    -H "Authorization: ${HMAC_AUTHORIZATION}" \
+    -d '{"name": "tampered"}'
+}
 ```
 
 您应该看到一个 `HTTP/1.1 401 Unauthorized` 响应,其中包含以下消息:

Reply via email to