You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by sp...@apache.org on 2020/10/04 11:58:06 UTC

[apisix] branch master updated: change(hmac-auth): update the organization of `signing_string` . (#2337)

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

spacewander 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 20c670c  change(hmac-auth): update the organization of `signing_string` . (#2337)
20c670c is described below

commit 20c670ce097af6bbd1bdb150f26faa77d582d61e
Author: YuanSheng Wang <me...@gmail.com>
AuthorDate: Sun Oct 4 19:57:57 2020 +0800

    change(hmac-auth): update the organization of `signing_string` . (#2337)
    
    fix #2336 .
    
    ref:
    https://help.aliyun.com/document_detail/29475.html?spm=a2c4g.11186623.2.15.62c73e789LVg02
    https://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html#RESTAuthenticationConstructingCanonicalizedAmzHeaders
---
 apisix/plugins/hmac-auth.lua    | 20 ++++++++------
 doc/plugins/hmac-auth.md        | 27 +++++++++++++++----
 doc/zh-cn/plugins/hmac-auth.md  | 26 ++++++++++++++----
 t/plugin/consumer-restriction.t | 50 ++++++++++++++++++++++++++++-------
 t/plugin/custom_hmac_auth.t     | 13 +++++++--
 t/plugin/hmac-auth.t            | 58 ++++++++++++++++++++++++++++++++---------
 6 files changed, 153 insertions(+), 41 deletions(-)

diff --git a/apisix/plugins/hmac-auth.lua b/apisix/plugins/hmac-auth.lua
index 0c37ad7..2c9d0ac 100644
--- a/apisix/plugins/hmac-auth.lua
+++ b/apisix/plugins/hmac-auth.lua
@@ -201,27 +201,31 @@ local function generate_signature(ctx, secret_key, params)
         canonical_query_string = core.table.concat(query_tab, "&")
     end
 
-    local canonical_headers = {}
-
     core.log.info("all headers: ",
                   core.json.delay_encode(core.request.headers(ctx), true))
 
+    local signing_string_items = {
+        request_method,
+        canonical_uri,
+        canonical_query_string,
+        params.access_key,
+        params.date,
+    }
+
     if params.signed_headers then
         for _, h in ipairs(params.signed_headers) do
             local canonical_header = core.request.header(ctx, h) or ""
-            core.table.insert(canonical_headers, canonical_header)
+            core.table.insert(signing_string_items,
+                              h .. ":" .. canonical_header)
             core.log.info("canonical_header name:", core.json.delay_encode(h))
             core.log.info("canonical_header value: ",
                           core.json.delay_encode(canonical_header))
         end
     end
 
-    local signing_string = request_method .. canonical_uri
-                            .. canonical_query_string
-                            .. params.access_key .. params.date
-                            .. core.table.concat(canonical_headers, "")
+    local signing_string = core.table.concat(signing_string_items, "\n")
 
-    core.log.info("signing_string:", signing_string,
+    core.log.info("signing_string: ", signing_string,
                   " params.signed_headers:",
                   core.json.delay_encode(params.signed_headers))
 
diff --git a/doc/plugins/hmac-auth.md b/doc/plugins/hmac-auth.md
index a3d31e2..753addd 100644
--- a/doc/plugins/hmac-auth.md
+++ b/doc/plugins/hmac-auth.md
@@ -20,13 +20,13 @@
 - [中文](../zh-cn/plugins/hmac-auth.md)
 
 # Summary
+
 - [**Name**](#name)
 - [**Attributes**](#attributes)
 - [**How To Enable**](#how-to-enable)
 - [**Test Plugin**](#test-plugin)
 - [**Disable Plugin**](#disable-plugin)
 
-
 ## Name
 
 `hmac-auth` is an authentication plugin that need to work with `consumer`. Add HMAC Authentication to a `service` or `route`.
@@ -83,7 +83,8 @@ curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f13
 ## Test Plugin
 
 ### generate signature:
-The calculation formula of the signature is `signature = HMAC-SHAx-HEX(secret_key, signing_string)`. From the formula, it can be seen that in order to obtain the signature, two parameters, `SECRET_KEY` and `signing_STRING`, are required. Where secret_key is configured by the corresponding consumer, the calculation formula of `signing_STRING` is `signing_string = HTTP Method + HTTP URI + canonical_query_string + access_key + Date + signed_headers_string`
+
+The calculation formula of the signature is `signature = HMAC-SHAx-HEX(secret_key, signing_string)`. From the formula, it can be seen that in order to obtain the signature, two parameters, `SECRET_KEY` and `signing_STRING`, are required. Where secret_key is configured by the corresponding consumer, the calculation formula of `signing_STRING` is `signing_string = signing_string = HTTP Method + \n + HTTP URI + \n + canonical_query_string + \n + access_key + \n + Date + \n + signed_headers_ [...]
 
 1. **HTTP Method** : Refers to the GET, PUT, POST and other request methods defined in the HTTP protocol, and must be in all uppercase.
 2. **HTTP URI** : `HTTP URI` requirements must start with "/", those that do not start with "/" need to be added, and the empty path is "/".
@@ -96,7 +97,6 @@ The calculation formula of the signature is `signature = HMAC-SHAx-HEX(secret_ke
 * Extract the `query` item in the URL, that is, the string "key1 = valve1 & key2 = valve2" after the "?" in the URL.
 * Split the `query` into several items according to the & separator, each item is in the form of key=value or only key.
 * Encoding each item after disassembly is divided into the following two situations.
-
     * When the item has only key, the conversion formula is UriEncode(key) + "=".
     * When the item is in the form of key=value, the conversion formula is in the form of UriEncode(key) + "=" + UriEncode(value). Here value can be an empty string.
     * After converting each item, sort by key in lexicographic order (ASCII code from small to large), and connect them with the & symbol to generate the corresponding canonical_query_string.
@@ -104,12 +104,29 @@ The calculation formula of the signature is `signature = HMAC-SHAx-HEX(secret_ke
 > The signed_headers_string generation steps are as follows:
 
 * Obtain the headers specified to be added to the calculation from the request header. For details, please refer to the placement of `SIGNED_HEADERS` in the next section `Use the generated signature to make a request attempt`.
-* Take out the headers specified by `SIGNED_HEADERS` in order from the request header, and splice them together in order. After splicing, a `signed_headers_string` is generated.
+* Take out the headers specified by `SIGNED_HEADERS` in order from the request header, and splice them together in order of `name:value`. After splicing, a `signed_headers_string` is generated.
+
+```plain
+HeaderKey1 + ":" + HeaderValue1 + "\n"\+
+HeaderKey2 + ":" + HeaderValue2 + "\n"\+
+...
+HeaderKeyN + ":" + HeaderValueN
+```
+
+Here is a full example:
+
+```plain
+GET
+/hello
+your-access-key
+Mon, 28 Sep 2020 06:48:57 GMT
+x-custom-header:value
+```
 
 ### Use the generated signature to try the request
 
 **Note: ACCESS_KEY, SIGNATURE, ALGORITHM, DATE, SIGNED_HEADERS respectively represent the corresponding variables**
-**Note: SIGNED_HEADERS is the headers specified by the client to join the encryption calculation, multiple separated by semicolons, Example: User-Agent;Accept-Language**
+**Note: SIGNED_HEADERS is the headers specified by the client to join the encryption calculation**
 
 * The signature information is put together in the request header `Authorization` field:
 
diff --git a/doc/zh-cn/plugins/hmac-auth.md b/doc/zh-cn/plugins/hmac-auth.md
index 912003f..8ce726f 100644
--- a/doc/zh-cn/plugins/hmac-auth.md
+++ b/doc/zh-cn/plugins/hmac-auth.md
@@ -20,13 +20,13 @@
 - [English](../../plugins/hmac-auth.md)
 
 # 目录
+
 - [**名字**](#名字)
 - [**属性**](#属性)
 - [**如何启用**](#如何启用)
 - [**测试插件**](#测试插件)
 - [**禁用插件**](#禁用插件)
 
-
 ## 名字
 
 `hmac-auth` 是一个认证插件,它需要与 `consumer` 一起配合才能工作。
@@ -43,7 +43,6 @@
 | clock_skew     | integer       | 可选   | 0           |                                             | 签名允许的时间偏移,以秒为单位的计时。比如允许时间偏移 10 秒钟,那么就应设置为 `10`。特别地,`0` 表示不对 `Date` 进行检查。                                                        |
 | signed_headers | array[string] | 可选   |               |                                             | 限制加入加密计算的 headers ,指定后客户端请求只能在此范围内指定 headers ,此项为空时将把所有客户端请求指定的 headers 加入加密计算。如: ["User-Agent", "Accept-Language", "x-custom-a"] |
 
-
 ## 如何启用
 
 1. 创建一个 consumer 对象,并设置插件 `hmac-auth` 的值。
@@ -85,7 +84,7 @@ curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f13
 
 ### 签名生成公式
 
-签名的计算公式为 `signature = HMAC-SHAx-HEX(secret_key, signing_string)`,从公式可以看出,想要获得签名需要得到 `secret_key` 和 `signing_string` 两个参数。其中 `secret_key` 为对应 consumer 所配置的, `signing_string` 的计算公式为 `signing_string = HTTP Method + HTTP URI + canonical_query_string + access_key + Date + signed_headers_string`
+签名的计算公式为 `signature = HMAC-SHAx-HEX(secret_key, signing_string)`,从公式可以看出,想要获得签名需要得到 `secret_key` 和 `signing_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`。
 
 1. **HTTP Method**:指 HTTP 协议中定义的 GET、PUT、POST 等请求方法,必须使用全大写的形式。
 2. **HTTP URI**:要求必须以“/”开头,不以“/”开头的需要补充上,空路径为“/”。
@@ -105,13 +104,30 @@ curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f13
 > signed_headers_string 生成步骤如下:
 
 * 从请求头中获取指定加入计算的 headers ,具体请参考下节 `使用生成好的签名进行请求尝试` 中的 `SIGNED_HEADERS` 放置的位置。
-* 从请求头中按顺序取出 `SIGNED_HEADERS` 指定的 headers ,并按顺序拼接起来,拼接完后就生成了 `signed_headers_string` 。
+* 从请求头中按顺序取出 `SIGNED_HEADERS` 指定的 headers ,并按顺序用`name:value`方式拼接起来,拼接完后就生成了 `signed_headers_string` 。
 
+```plain
+HeaderKey1 + ":" + HeaderValue1 + "\n"\+
+HeaderKey2 + ":" + HeaderValue2 + "\n"\+
+...
+HeaderKeyN + ":" + HeaderValueN
+```
+
+拼接后的示例:
+
+```plain
+GET
+/hello
+
+your-access-key
+Mon, 28 Sep 2020 06:48:57 GMT
+x-custom-header:value
+```
 
 ### 使用生成好的签名进行请求尝试
 
 **注: ACCESS_KEY, SIGNATURE, ALGORITHM, DATE, SIGNED_HEADERS 分别代表对应的变量**
-**注: SIGNED_HEADERS 为客户端指定的加入加密计算的 headers ,多个以英文分号分隔如:User-Agent;Accept-Language**
+**注: SIGNED_HEADERS 为客户端指定的加入加密计算的 headers**
 
 * 签名信息拼一起放到请求头 `Authorization` 字段中:
 
diff --git a/t/plugin/consumer-restriction.t b/t/plugin/consumer-restriction.t
index 491de4e..afa7492 100644
--- a/t/plugin/consumer-restriction.t
+++ b/t/plugin/consumer-restriction.t
@@ -723,8 +723,16 @@ location /t {
         local custom_header_a = "asld$%dfasf"
         local custom_header_b = "23879fmsldfk"
 
-        local signing_string = "GET" .. "/hello" ..  "" ..
-            access_key .. gmt .. custom_header_a .. custom_header_b
+        local signing_string = {
+            "GET",
+            "/hello",
+            "",
+            access_key,
+            gmt,
+            "x-custom-header-a:" .. custom_header_a,
+            "x-custom-header-b:" .. custom_header_b
+        }
+        signing_string = core.table.concat(signing_string, "\n")
 
         local signature = hmac:new(secret_key, hmac.ALGOS.SHA256):final(signing_string)
         core.log.info("signature:", ngx_encode_base64(signature))
@@ -880,8 +888,16 @@ location /t {
         local custom_header_a = "asld$%dfasf"
         local custom_header_b = "23879fmsldfk"
 
-        local signing_string = "GET" .. "/hello" ..  "" ..
-            access_key .. gmt .. custom_header_a .. custom_header_b
+        local signing_string = {
+            "GET",
+            "/hello",
+            "",
+            access_key,
+            gmt,
+            "x-custom-header-a:" .. custom_header_a,
+            "x-custom-header-b:" .. custom_header_b
+        }
+        signing_string = core.table.concat(signing_string, "\n")
 
         local signature = hmac:new(secret_key, hmac.ALGOS.SHA256):final(signing_string)
         core.log.info("signature:", ngx_encode_base64(signature))
@@ -903,7 +919,7 @@ location /t {
         if code >= 300 then
             ngx.status = code
         end
-        
+
         ngx.say(body)
     }
 }
@@ -1051,8 +1067,16 @@ location /t {
         local custom_header_a = "asld$%dfasf"
         local custom_header_b = "23879fmsldfk"
 
-        local signing_string = "GET" .. "/hello" ..  "" ..
-            access_key .. gmt .. custom_header_a .. custom_header_b
+        local signing_string = {
+            "GET",
+            "/hello",
+            "",
+            access_key,
+            gmt,
+            "x-custom-header-a:" .. custom_header_a,
+            "x-custom-header-b:" .. custom_header_b
+        }
+        signing_string = core.table.concat(signing_string, "\n")
 
         local signature = hmac:new(secret_key, hmac.ALGOS.SHA256):final(signing_string)
         core.log.info("signature:", ngx_encode_base64(signature))
@@ -1163,8 +1187,16 @@ location /t {
         local custom_header_a = "asld$%dfasf"
         local custom_header_b = "23879fmsldfk"
 
-        local signing_string = "GET" .. "/hello" ..  "" ..
-            access_key .. gmt .. custom_header_a .. custom_header_b
+        local signing_string = {
+            "GET",
+            "/hello",
+            "",
+            access_key,
+            gmt,
+            "x-custom-header-a:" .. custom_header_a,
+            "x-custom-header-b:" .. custom_header_b
+        }
+        signing_string = core.table.concat(signing_string, "\n")
 
         local signature = hmac:new(secret_key, hmac.ALGOS.SHA256):final(signing_string)
         core.log.info("signature:", ngx_encode_base64(signature))
diff --git a/t/plugin/custom_hmac_auth.t b/t/plugin/custom_hmac_auth.t
index e02705b..3fc4751 100644
--- a/t/plugin/custom_hmac_auth.t
+++ b/t/plugin/custom_hmac_auth.t
@@ -244,8 +244,17 @@ location /t {
         local access_key = "my-access-key"
         local custom_header_a = "asld$%dfasf"
         local custom_header_b = "23879fmsldfk"
-        local signing_string = "GET" .. "/hello" ..  "" ..
-            access_key .. gmt .. custom_header_a .. custom_header_b
+
+        local signing_string = {
+            "GET",
+            "/hello",
+            "",
+            access_key,
+            gmt,
+            "x-custom-header-a:" .. custom_header_a,
+            "x-custom-header-b:" .. custom_header_b
+        }
+        signing_string = core.table.concat(signing_string, "\n")
 
         local signature = hmac:new(secret_key, hmac.ALGOS.SHA256):final(signing_string)
         core.log.info("signature:", ngx_encode_base64(signature))
diff --git a/t/plugin/hmac-auth.t b/t/plugin/hmac-auth.t
index efdf9f0..fee4598 100644
--- a/t/plugin/hmac-auth.t
+++ b/t/plugin/hmac-auth.t
@@ -338,8 +338,17 @@ location /t {
         local custom_header_a = "asld$%dfasf"
         local custom_header_b = "23879fmsldfk"
 
-        local signing_string = "GET" .. "/hello" ..  "" ..
-            access_key .. gmt .. custom_header_a .. custom_header_b
+        local signing_string = {
+            "GET",
+            "/hello",
+            "",
+            access_key,
+            gmt,
+            "x-custom-header-a:" .. custom_header_a,
+            "x-custom-header-b:" .. custom_header_b
+        }
+        signing_string = core.table.concat(signing_string, "\n")
+        core.log.info("signing_string:", signing_string)
 
         local signature = hmac:new(secret_key, hmac.ALGOS.SHA256):final(signing_string)
         core.log.info("signature:", ngx_encode_base64(signature))
@@ -501,7 +510,7 @@ location /t {
         local access_key = "my-access-key2"
         local custom_header_a = "asld$%dfasf"
         local custom_header_b = "23879fmsldfk"
-        
+
         ngx.sleep(2)
 
         local signing_string = "GET" .. "/hello" ..  "" ..
@@ -561,8 +570,17 @@ location /t {
         local custom_header_a = "asld$%dfasf"
         local custom_header_b = "23879fmsldfk"
 
-        local signing_string = "PUT" .. "/hello" ..  "" ..
-            access_key .. gmt .. custom_header_a .. custom_header_b
+        local signing_string = {
+            "PUT",
+            "/hello",
+            "",
+            access_key,
+            gmt,
+            "x-custom-header-a:" .. custom_header_a,
+            "x-custom-header-b:" .. custom_header_b
+        }
+        signing_string = core.table.concat(signing_string, "\n")
+        core.log.info("signing_string:", signing_string)
 
         local signature = hmac:new(secret_key, hmac.ALGOS.SHA256):final(signing_string)
         core.log.info("signature:", ngx_encode_base64(signature))
@@ -617,19 +635,28 @@ location /t {
         local custom_header_a = "asld$%dfasf"
         local custom_header_b = "23879fmsldfk"
 
-        local signing_string = "PUT" .. "/hello" ..  "" ..
-            access_key .. gmt .. custom_header_a .. custom_header_b
+        local signing_string = {
+            "PUT",
+            "/hello",
+            "",
+            access_key,
+            gmt,
+            "x-custom-header-a:" .. custom_header_a,
+            "x-custom-header-b:" .. custom_header_b
+        }
+        signing_string = core.table.concat(signing_string, "\n")
+
         core.log.info("signing_string:", signing_string)
         local signature = hmac:new(secret_key, hmac.ALGOS.SHA256):final(signing_string)
         core.log.info("signature:", ngx_encode_base64(signature))
         local auth_string = "hmac-auth-v1#" .. access_key .. "#" .. ngx_encode_base64(signature) .. "#" ..
         "hmac-sha256#" .. gmt .. "#x-custom-header-a;x-custom-header-b"
-        
+
         local headers = {}
         headers["Authorization"] = auth_string
         headers["x-custom-header-a"] = custom_header_a
-        headers["x-custom-header-b"] = custom_header_b        
-        
+        headers["x-custom-header-b"] = custom_header_b
+
         local code, body = t.test('/hello',
             ngx.HTTP_PUT,
             req_body,
@@ -780,8 +807,15 @@ location /t {
         local access_key = "my-access-key5"
         local custom_header_a = "asld$%dfasf"
 
-        local signing_string = "GET" .. "/hello" ..  "" ..
-            access_key .. gmt .. custom_header_a
+        local signing_string = {
+            "GET",
+            "/hello",
+            "",
+            access_key,
+            gmt,
+            "x-custom-header-a:" .. custom_header_a
+        }
+        signing_string = core.table.concat(signing_string, "\n")
 
         local signature = hmac:new(secret_key, hmac.ALGOS.SHA256):final(signing_string)
         core.log.info("signature:", ngx_encode_base64(signature))