You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by me...@apache.org on 2020/09/28 01:10:35 UTC

[apisix] branch master updated: feat: replace timestamp with date and time in GMT format in plugin `hmac-auth` (#2301)

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

membphis 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 c375bd0  feat: replace timestamp with date and time in GMT format in plugin `hmac-auth` (#2301)
c375bd0 is described below

commit c375bd0cac6de4470782fa964323960e798cca40
Author: nic-chen <33...@users.noreply.github.com>
AuthorDate: Mon Sep 28 09:10:26 2020 +0800

    feat: replace timestamp with date and time in GMT format in plugin `hmac-auth` (#2301)
---
 apisix/plugins/hmac-auth.lua    |  30 ++++++-----
 doc/plugins/hmac-auth.md        |  43 ++++++++++++---
 doc/zh-cn/plugins/hmac-auth.md  |  44 ++++++++++++---
 t/APISIX.pm                     |   2 +-
 t/plugin/consumer-restriction.t |  30 +++++++----
 t/plugin/custom_hmac_auth.t     |  39 ++++++++------
 t/plugin/hmac-auth.t            | 116 +++++++++++++++++++++++++++-------------
 7 files changed, 213 insertions(+), 91 deletions(-)

diff --git a/apisix/plugins/hmac-auth.lua b/apisix/plugins/hmac-auth.lua
index 33c1ddf..0c37ad7 100644
--- a/apisix/plugins/hmac-auth.lua
+++ b/apisix/plugins/hmac-auth.lua
@@ -32,7 +32,7 @@ local ngx_decode_base64 = ngx.decode_base64
 
 local SIGNATURE_KEY = "X-HMAC-SIGNATURE"
 local ALGORITHM_KEY = "X-HMAC-ALGORITHM"
-local TIMESTAMP_KEY = "X-HMAC-TIMESTAMP"
+local DATE_KEY = "Date"
 local ACCESS_KEY    = "X-HMAC-ACCESS-KEY"
 local SIGNED_HEADERS_KEY = "X-HMAC-SIGNED-HEADERS"
 local plugin_name   = "hmac-auth"
@@ -57,7 +57,7 @@ local schema = {
                 },
                 clock_skew = {
                     type = "integer",
-                    default = 300
+                    default = 0
                 },
                 signed_headers = {
                     type = "array",
@@ -218,7 +218,7 @@ local function generate_signature(ctx, secret_key, params)
 
     local signing_string = request_method .. canonical_uri
                             .. canonical_query_string
-                            .. params.access_key .. params.timestamp
+                            .. params.access_key .. params.date
                             .. core.table.concat(canonical_headers, "")
 
     core.log.info("signing_string:", signing_string,
@@ -246,10 +246,16 @@ local function validate(ctx, params)
 
     core.log.info("clock_skew: ", conf.clock_skew)
     if conf.clock_skew and conf.clock_skew > 0 then
-        local diff = abs(ngx_time() - params.timestamp)
-        core.log.info("timestamp diff: ", diff)
+        local time = ngx.parse_http_time(params.date)
+        core.log.info("params.date: ", params.date, " time: ", time)
+        if not time then
+            return nil, {message = "Invalid GMT format time"}
+        end
+
+        local diff = abs(ngx_time() - time)
+        core.log.info("gmt diff: ", diff)
         if diff > conf.clock_skew then
-          return nil, {message = "Invalid timestamp"}
+            return nil, {message = "Clock skew exceeded"}
         end
     end
 
@@ -285,7 +291,7 @@ local function get_params(ctx)
     local access_key = ACCESS_KEY
     local signature_key = SIGNATURE_KEY
     local algorithm_key = ALGORITHM_KEY
-    local timestamp_key = TIMESTAMP_KEY
+    local date_key = DATE_KEY
     local signed_headers_key = SIGNED_HEADERS_KEY
 
     if try_attr(local_conf, "plugin_attr", "hmac-auth") then
@@ -293,14 +299,14 @@ local function get_params(ctx)
         access_key = attr.access_key or access_key
         signature_key = attr.signature_key or signature_key
         algorithm_key = attr.algorithm_key or algorithm_key
-        timestamp_key = attr.timestamp_key or timestamp_key
+        date_key = attr.date_key or date_key
         signed_headers_key = attr.signed_headers_key or signed_headers_key
     end
 
     local app_key = core.request.header(ctx, access_key)
     local signature = core.request.header(ctx, signature_key)
     local algorithm = core.request.header(ctx, algorithm_key)
-    local timestamp = core.request.header(ctx, timestamp_key)
+    local date = core.request.header(ctx, date_key)
     local signed_headers = core.request.header(ctx, signed_headers_key)
     core.log.info("signature_key: ", signature_key)
 
@@ -316,11 +322,11 @@ local function get_params(ctx)
                       #auth_data, " auth_data: ",
                       core.json.delay_encode(auth_data))
 
-        if #auth_data == 6 and auth_data[1] == "hmac-auth-v2" then
+        if #auth_data == 6 and auth_data[1] == "hmac-auth-v1" then
             app_key = auth_data[2]
             signature = auth_data[3]
             algorithm = auth_data[4]
-            timestamp = auth_data[5]
+            date = auth_data[5]
             signed_headers = auth_data[6]
         end
     end
@@ -328,7 +334,7 @@ local function get_params(ctx)
     params.access_key = app_key
     params.algorithm  = algorithm
     params.signature  = signature
-    params.timestamp  = timestamp or 0
+    params.date  = date or ""
     params.signed_headers = signed_headers and ngx_re.split(signed_headers, ";")
 
     core.log.info("params: ", core.json.delay_encode(params))
diff --git a/doc/plugins/hmac-auth.md b/doc/plugins/hmac-auth.md
index 2093dcc..a3d31e2 100644
--- a/doc/plugins/hmac-auth.md
+++ b/doc/plugins/hmac-auth.md
@@ -40,7 +40,7 @@ The `consumer` then adds its key to request header to verify its request.
 | access_key     | string        | required    |               |                                             | Different `consumer` objects should have different values, and it should be unique. If different consumers use the same `access_key`, a request matching exception will occur.                                                                                                |
 | secret_key     | string        | required    |               |                                             | Use as a pair with `access_key`.                                                                                                                                                                                                                                              |
 | algorithm      | string        | optional    | "hmac-sha256" | ["hmac-sha1", "hmac-sha256", "hmac-sha512"] | Encryption algorithm.                                                                                                                                                                                                                                                         |
-| clock_skew     | integer       | optional    | 300           |                                             | The clock skew allowed by the signature in seconds. For example, if the time is allowed to skew by 10 seconds, then it should be set to `10`. especially, `0` means not checking timestamp                                                                                    |
+| clock_skew     | integer       | optional    | 0           |                                             | The clock skew allowed by the signature in seconds. For example, if the time is allowed to skew by 10 seconds, then it should be set to `10`. especially, `0` means not checking `Date`                                                                                    |
 | signed_headers | array[string] | optional    |               |                                             | Restrict the headers that are added to the encrypted calculation. After the specified, the client request can only specify the headers within this range. When this item is empty, all the headers specified by the client request will be added to the encrypted calculation |
 
 ## How To Enable
@@ -83,12 +83,13 @@ 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 + timestamp + 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 = HTTP Method + HTTP URI + canonical_query_string + access_key + Date + signed_headers_string`
 
 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 "/".
-3. **canonical_query_string** :`canonical_query_string` is the result of encoding the `query` in the URL (`query` is the string "key1 = valve1 & key2 = valve2" after the "?" in the URL).
-4. **signed_headers_string** :`signed_headers_string` is the result of obtaining the fields specified by the client from the request header and concatenating the strings in order.
+3. **Date** : Date in http header(GMT format).
+4. **canonical_query_string** :`canonical_query_string` is the result of encoding the `query` in the URL (`query` is the string "key1 = valve1 & key2 = valve2" after the "?" in the URL).
+5. **signed_headers_string** :`signed_headers_string` is the result of obtaining the fields specified by the client from the request header and concatenating the strings in order.
 
 > The coding steps are as follows:
 
@@ -107,13 +108,13 @@ The calculation formula of the signature is `signature = HMAC-SHAx-HEX(secret_ke
 
 ### Use the generated signature to try the request
 
-**Note: ACCESS_KEY, SIGNATURE, ALGORITHM, TIMESTAMP, SIGNED_HEADERS respectively represent the corresponding variables**
+**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**
 
 * The signature information is put together in the request header `Authorization` field:
 
 ```shell
-$ curl http://127.0.0.1:9080/index.html -H 'Authorization: hmac-auth-v1# + ACCESS_KEY + # + base64_encode(SIGNATURE) + # + ALGORITHM + # + TIMESTAMP + # + SIGNED_HEADERS' -i
+$ curl http://127.0.0.1:9080/index.html -H 'Authorization: hmac-auth-v1# + ACCESS_KEY + # + base64_encode(SIGNATURE) + # + ALGORITHM + # + DATE + # + SIGNED_HEADERS' -i
 HTTP/1.1 200 OK
 Content-Type: text/html
 Content-Length: 13175
@@ -128,7 +129,35 @@ Accept-Ranges: bytes
 * The signature information is separately placed in the request header:
 
 ```shell
-$ curl http://127.0.0.1:9080/index.html -H 'X-HMAC-SIGNATURE: base64_encode(SIGNATURE)' -H 'X-HMAC-ALGORITHM: ALGORITHM' -H 'X-HMAC-TIMESTAMP: TIMESTAMP' -H 'X-HMAC-ACCESS-KEY: ACCESS_KEY' -H 'X-HMAC-SIGNED-HEADERS: SIGNED_HEADERS' -i
+$ curl http://127.0.0.1:9080/index.html -H 'X-HMAC-SIGNATURE: base64_encode(SIGNATURE)' -H 'X-HMAC-ALGORITHM: ALGORITHM' -H 'Date: DATE' -H 'X-HMAC-ACCESS-KEY: ACCESS_KEY' -H 'X-HMAC-SIGNED-HEADERS: SIGNED_HEADERS' -i
+HTTP/1.1 200 OK
+Content-Type: text/html
+Content-Length: 13175
+...
+Accept-Ranges: bytes
+
+<!DOCTYPE html>
+<html lang="cn">
+```
+
+## Custom header key
+
+We can customize header key for auth parameters by adding the attribute configuration of the plugin under `plugin_attr` in `conf / config.yaml`.
+
+```yaml
+plugin_attr:
+  hmac-auth:
+    signature_key: X-APISIX-HMAC-SIGNATURE
+    algorithm_key: X-APISIX-HMAC-ALGORITHM
+    date_key: X-APISIX-DATE
+    access_key: X-APISIX-HMAC-ACCESS-KEY
+    signed_headers_key: X-APISIX-HMAC-SIGNED-HEADERS
+```
+
+**After customizing the header, request example:**
+
+```shell
+$ curl http://127.0.0.1:9080/index.html -H 'X-APISIX-HMAC-SIGNATURE: base64_encode(SIGNATURE)' -H 'X-APISIX-HMAC-ALGORITHM: ALGORITHM' -H 'X-APISIX-DATE: DATE' -H 'X-APISIX-HMAC-ACCESS-KEY: ACCESS_KEY' -H 'X-APISIX-HMAC-SIGNED-HEADERS: SIGNED_HEADERS' -i
 HTTP/1.1 200 OK
 Content-Type: text/html
 Content-Length: 13175
diff --git a/doc/zh-cn/plugins/hmac-auth.md b/doc/zh-cn/plugins/hmac-auth.md
index 3024373..912003f 100644
--- a/doc/zh-cn/plugins/hmac-auth.md
+++ b/doc/zh-cn/plugins/hmac-auth.md
@@ -40,7 +40,7 @@
 | access_key     | string        | 必须   |               |                                             | 不同的 `consumer` 对象应有不同的值,它应当是唯一的。不同 consumer 使用了相同的 `access_key` ,将会出现请求匹配异常。                                                                    |
 | secret_key     | string        | 必须   |               |                                             | 与 `access_key` 配对使用。                                                                                                                                                              |
 | algorithm      | string        | 可选   | "hmac-sha256" | ["hmac-sha1", "hmac-sha256", "hmac-sha512"] | 加密算法。                                                                                                                                                                              |
-| clock_skew     | integer       | 可选   | 300           |                                             | 签名允许的时间偏移,以秒为单位的计时。比如允许时间偏移 10 秒钟,那么就应设置为 `10`。特别地,`0` 表示不对 `timestamp` 进行检查。                                                        |
+| clock_skew     | integer       | 可选   | 0           |                                             | 签名允许的时间偏移,以秒为单位的计时。比如允许时间偏移 10 秒钟,那么就应设置为 `10`。特别地,`0` 表示不对 `Date` 进行检查。                                                        |
 | signed_headers | array[string] | 可选   |               |                                             | 限制加入加密计算的 headers ,指定后客户端请求只能在此范围内指定 headers ,此项为空时将把所有客户端请求指定的 headers 加入加密计算。如: ["User-Agent", "Accept-Language", "x-custom-a"] |
 
 
@@ -85,12 +85,13 @@ 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 + timestamp + signed_headers_string`
+签名的计算公式为 `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`
 
 1. **HTTP Method**:指 HTTP 协议中定义的 GET、PUT、POST 等请求方法,必须使用全大写的形式。
 2. **HTTP URI**:要求必须以“/”开头,不以“/”开头的需要补充上,空路径为“/”。
-3. **canonical_query_string**:是对于 URL 中的 query( query 即 URL 中 ? 后面的 key1=valve1&key2=valve2 字符串)进行编码后的结果。
-4. **signed_headers_string**:是从请求头中获取客户端指定的字段,并按顺序拼接字符串的结果。
+3. **Date**:请求头中的 Date ( GMT 格式 )。
+4. **canonical_query_string**:是对于 URL 中的 query( query 即 URL 中 ? 后面的 key1=valve1&key2=valve2 字符串)进行编码后的结果。
+5. **signed_headers_string**:是从请求头中获取客户端指定的字段,并按顺序拼接字符串的结果。
 
 > canonical_query_string 编码步骤如下:
 
@@ -109,13 +110,13 @@ curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f13
 
 ### 使用生成好的签名进行请求尝试
 
-**注: ACCESS_KEY, SIGNATURE, ALGORITHM, TIMESTAMP, SIGNED_HEADERS 分别代表对应的变量**
+**注: ACCESS_KEY, SIGNATURE, ALGORITHM, DATE, SIGNED_HEADERS 分别代表对应的变量**
 **注: SIGNED_HEADERS 为客户端指定的加入加密计算的 headers ,多个以英文分号分隔如:User-Agent;Accept-Language**
 
 * 签名信息拼一起放到请求头 `Authorization` 字段中:
 
 ```shell
-$ curl http://127.0.0.1:9080/index.html -H 'Authorization: hmac-auth-v1# + ACCESS_KEY + # + base64_encode(SIGNATURE) + # + ALGORITHM + # + TIMESTAMP + # + SIGNED_HEADERS' -i
+$ curl http://127.0.0.1:9080/index.html -H 'Authorization: hmac-auth-v1# + ACCESS_KEY + # + base64_encode(SIGNATURE) + # + ALGORITHM + # + DATE + # + SIGNED_HEADERS' -i
 HTTP/1.1 200 OK
 Content-Type: text/html
 Content-Length: 13175
@@ -130,7 +131,36 @@ Accept-Ranges: bytes
 * 签名信息分开分别放到请求头:
 
 ```shell
-$ curl http://127.0.0.1:9080/index.html -H 'X-HMAC-SIGNATURE: base64_encode(SIGNATURE)' -H 'X-HMAC-ALGORITHM: ALGORITHM' -H 'X-HMAC-TIMESTAMP: TIMESTAMP' -H 'X-HMAC-ACCESS-KEY: ACCESS_KEY' -H 'X-HMAC-SIGNED-HEADERS: SIGNED_HEADERS' -i
+$ curl http://127.0.0.1:9080/index.html -H 'X-HMAC-SIGNATURE: base64_encode(SIGNATURE)' -H 'X-HMAC-ALGORITHM: ALGORITHM' -H 'Date: DATE' -H 'X-HMAC-ACCESS-KEY: ACCESS_KEY' -H 'X-HMAC-SIGNED-HEADERS: SIGNED_HEADERS' -i
+HTTP/1.1 200 OK
+Content-Type: text/html
+Content-Length: 13175
+...
+Accept-Ranges: bytes
+
+<!DOCTYPE html>
+<html lang="cn">
+```
+
+
+## 自定义 header 名称
+
+我们可以在 `conf/config.yaml` 中,`plugin_attr` 下添加插件的属性配置来自定义参数 header 名称。
+
+```yaml
+plugin_attr:
+  hmac-auth:
+    signature_key: X-APISIX-HMAC-SIGNATURE
+    algorithm_key: X-APISIX-HMAC-ALGORITHM
+    date_key: X-APISIX-DATE
+    access_key: X-APISIX-HMAC-ACCESS-KEY
+    signed_headers_key: X-APISIX-HMAC-SIGNED-HEADERS
+```
+
+**自定义 header 后,请求示例:**
+
+```shell
+$ curl http://127.0.0.1:9080/index.html -H 'X-APISIX-HMAC-SIGNATURE: base64_encode(SIGNATURE)' -H 'X-APISIX-HMAC-ALGORITHM: ALGORITHM' -H 'X-APISIX-DATE: DATE' -H 'X-APISIX-HMAC-ACCESS-KEY: ACCESS_KEY' -H 'X-APISIX-HMAC-SIGNED-HEADERS: SIGNED_HEADERS' -i
 HTTP/1.1 200 OK
 Content-Type: text/html
 Content-Length: 13175
diff --git a/t/APISIX.pm b/t/APISIX.pm
index d577228..c951cd9 100644
--- a/t/APISIX.pm
+++ b/t/APISIX.pm
@@ -103,7 +103,7 @@ plugin_attr:
   hmac-auth:
     signature_key: X-APISIX-HMAC-SIGNATURE
     algorithm_key: X-APISIX-HMAC-ALGORITHM
-    timestamp_key: X-APISIX-HMAC-TIMESTAMP
+    date_key: X-APISIX-DATE
     access_key: X-APISIX-HMAC-ACCESS-KEY
     signed_headers_key: X-APISIX-HMAC-SIGNED-HEADERS
 _EOC_
diff --git a/t/plugin/consumer-restriction.t b/t/plugin/consumer-restriction.t
index 69708ea..f93cb16 100644
--- a/t/plugin/consumer-restriction.t
+++ b/t/plugin/consumer-restriction.t
@@ -619,7 +619,7 @@ passed
                                     "access_key": "my-access-key",
                                     "secret_key": "my-secret-key",
                                     "algorithm": "hmac-sha256",
-                                    "clock_skew": 300
+                                    "clock_skew": 0
                                 },
                                 "consumer-restriction": {
                                     "type": "service_id",
@@ -709,7 +709,8 @@ passed
 --- config
 location /t {
     content_by_lua_block {
-        local ngx_time   = ngx.time
+        local ngx_time = ngx.time
+        local ngx_http_time = ngx.http_time
         local core = require("apisix.core")
         local t = require("lib.test_admin")
         local hmac = require("resty.hmac")
@@ -717,19 +718,20 @@ location /t {
 
         local secret_key = "my-secret-key"
         local timestamp = ngx_time()
+        local gmt = ngx_http_time(timestamp)
         local access_key = "my-access-key"
         local custom_header_a = "asld$%dfasf"
         local custom_header_b = "23879fmsldfk"
 
         local signing_string = "GET" .. "/hello" ..  "" ..
-            access_key .. timestamp .. custom_header_a .. custom_header_b
+            access_key .. gmt .. custom_header_a .. custom_header_b
 
         local signature = hmac:new(secret_key, hmac.ALGOS.SHA256):final(signing_string)
         core.log.info("signature:", ngx_encode_base64(signature))
         local headers = {}
         headers["X-HMAC-SIGNATURE"] = ngx_encode_base64(signature)
         headers["X-HMAC-ALGORITHM"] = "hmac-sha256"
-        headers["X-HMAC-TIMESTAMP"] = timestamp
+        headers["Date"] = gmt
         headers["X-HMAC-ACCESS-KEY"] = access_key
         headers["X-HMAC-SIGNED-HEADERS"] = "x-custom-header-a;x-custom-header-b"
         headers["x-custom-header-a"] = custom_header_a
@@ -865,6 +867,7 @@ passed
 location /t {
     content_by_lua_block {
         local ngx_time   = ngx.time
+        local ngx_http_time = ngx.http_time
         local core = require("apisix.core")
         local t = require("lib.test_admin")
         local hmac = require("resty.hmac")
@@ -872,19 +875,20 @@ location /t {
 
         local secret_key = "my-secret-key"
         local timestamp = ngx_time()
+        local gmt = ngx_http_time(timestamp)
         local access_key = "my-access-key"
         local custom_header_a = "asld$%dfasf"
         local custom_header_b = "23879fmsldfk"
 
         local signing_string = "GET" .. "/hello" ..  "" ..
-            access_key .. timestamp .. custom_header_a .. custom_header_b
+            access_key .. gmt .. custom_header_a .. custom_header_b
 
         local signature = hmac:new(secret_key, hmac.ALGOS.SHA256):final(signing_string)
         core.log.info("signature:", ngx_encode_base64(signature))
         local headers = {}
         headers["X-HMAC-SIGNATURE"] = ngx_encode_base64(signature)
         headers["X-HMAC-ALGORITHM"] = "hmac-sha256"
-        headers["X-HMAC-TIMESTAMP"] = timestamp
+        headers["Date"] = gmt
         headers["X-HMAC-ACCESS-KEY"] = access_key
         headers["X-HMAC-SIGNED-HEADERS"] = "x-custom-header-a;x-custom-header-b"
         headers["x-custom-header-a"] = custom_header_a
@@ -943,7 +947,7 @@ qr/\{"message":"The service_id is forbidden."\}/
                                     "access_key": "my-access-key",
                                     "secret_key": "my-secret-key",
                                     "algorithm": "hmac-sha256",
-                                    "clock_skew": 300
+                                    "clock_skew": 0
                                 },
                                 "consumer-restriction": {
                                     "type": "service_id",
@@ -1034,6 +1038,7 @@ passed
 location /t {
     content_by_lua_block {
         local ngx_time   = ngx.time
+        local ngx_http_time = ngx.http_time
         local core = require("apisix.core")
         local t = require("lib.test_admin")
         local hmac = require("resty.hmac")
@@ -1041,19 +1046,20 @@ location /t {
 
         local secret_key = "my-secret-key"
         local timestamp = ngx_time()
+        local gmt = ngx_http_time(timestamp)
         local access_key = "my-access-key"
         local custom_header_a = "asld$%dfasf"
         local custom_header_b = "23879fmsldfk"
 
         local signing_string = "GET" .. "/hello" ..  "" ..
-            access_key .. timestamp .. custom_header_a .. custom_header_b
+            access_key .. gmt .. custom_header_a .. custom_header_b
 
         local signature = hmac:new(secret_key, hmac.ALGOS.SHA256):final(signing_string)
         core.log.info("signature:", ngx_encode_base64(signature))
         local headers = {}
         headers["X-HMAC-SIGNATURE"] = ngx_encode_base64(signature)
         headers["X-HMAC-ALGORITHM"] = "hmac-sha256"
-        headers["X-HMAC-TIMESTAMP"] = timestamp
+        headers["Date"] = gmt
         headers["X-HMAC-ACCESS-KEY"] = access_key
         headers["X-HMAC-SIGNED-HEADERS"] = "x-custom-header-a;x-custom-header-b"
         headers["x-custom-header-a"] = custom_header_a
@@ -1143,6 +1149,7 @@ passed
 location /t {
     content_by_lua_block {
         local ngx_time   = ngx.time
+        local ngx_http_time = ngx.http_time
         local core = require("apisix.core")
         local t = require("lib.test_admin")
         local hmac = require("resty.hmac")
@@ -1150,19 +1157,20 @@ location /t {
 
         local secret_key = "my-secret-key"
         local timestamp = ngx_time()
+        local gmt = ngx_http_time(timestamp)
         local access_key = "my-access-key"
         local custom_header_a = "asld$%dfasf"
         local custom_header_b = "23879fmsldfk"
 
         local signing_string = "GET" .. "/hello" ..  "" ..
-            access_key .. timestamp .. custom_header_a .. custom_header_b
+            access_key .. gmt .. custom_header_a .. custom_header_b
 
         local signature = hmac:new(secret_key, hmac.ALGOS.SHA256):final(signing_string)
         core.log.info("signature:", ngx_encode_base64(signature))
         local headers = {}
         headers["X-HMAC-SIGNATURE"] = ngx_encode_base64(signature)
         headers["X-HMAC-ALGORITHM"] = "hmac-sha256"
-        headers["X-HMAC-TIMESTAMP"] = timestamp
+        headers["Date"] = gmt
         headers["X-HMAC-ACCESS-KEY"] = access_key
         headers["X-HMAC-SIGNED-HEADERS"] = "x-custom-header-a;x-custom-header-b"
         headers["x-custom-header-a"] = custom_header_a
diff --git a/t/plugin/custom_hmac_auth.t b/t/plugin/custom_hmac_auth.t
index 49e3287..e02705b 100644
--- a/t/plugin/custom_hmac_auth.t
+++ b/t/plugin/custom_hmac_auth.t
@@ -40,7 +40,8 @@ __DATA__
                     "plugins": {
                         "hmac-auth": {
                             "access_key": "my-access-key",
-                            "secret_key": "my-secret-key"
+                            "secret_key": "my-secret-key",
+                            "clock_skew": 10
                         }
                     }
                 }]],
@@ -53,7 +54,7 @@ __DATA__
                                     "access_key": "my-access-key",
                                     "secret_key": "my-secret-key",
                                     "algorithm": "hmac-sha256",
-                                    "clock_skew": 300
+                                    "clock_skew": 10
                                 }
                             }
                         }
@@ -184,7 +185,7 @@ GET /hello
 --- more_headers
 X-APISIX-HMAC-SIGNATURE: asdf
 X-APISIX-HMAC-ALGORITHM: hmac-sha256
-X-APISIX-HMAC-TIMESTAMP: 112
+X-APISIX-Date: Thu, 24 Sep 2020 06:39:52 GMT
 X-APISIX-HMAC-ACCESS-KEY: sdf
 --- error_code: 401
 --- response_body
@@ -200,7 +201,7 @@ GET /hello
 --- more_headers
 X-APISIX-HMAC-SIGNATURE: asdf
 X-APISIX-HMAC-ALGORITHM: ljlj
-X-APISIX-HMAC-TIMESTAMP: 112
+X-APISIX-Date: Thu, 24 Sep 2020 06:39:52 GMT
 X-APISIX-HMAC-ACCESS-KEY: sdf
 --- error_code: 401
 --- response_body
@@ -210,17 +211,17 @@ X-APISIX-HMAC-ACCESS-KEY: sdf
 
 
 
-=== TEST 8: verify: invalid timestamp
+=== TEST 8: verify: Invalid GMT format time
 --- request
 GET /hello
 --- more_headers
 X-APISIX-HMAC-SIGNATURE: asdf
 X-APISIX-HMAC-ALGORITHM: hmac-sha256
-X-APISIX-HMAC-TIMESTAMP: 112
+X-APISIX-Date: adfa
 X-APISIX-HMAC-ACCESS-KEY: my-access-key
 --- error_code: 401
 --- response_body
-{"message":"Invalid timestamp"}
+{"message":"Invalid GMT format time"}
 --- no_error_log
 [error]
 
@@ -230,26 +231,28 @@ X-APISIX-HMAC-ACCESS-KEY: my-access-key
 --- config
 location /t {
     content_by_lua_block {
-        local ngx_time   = ngx.time
+        local ngx_time = ngx.time
+        local ngx_http_time = ngx.http_time
         local core = require("apisix.core")
         local t = require("lib.test_admin")
         local hmac = require("resty.hmac")
         local ngx_encode_base64 = ngx.encode_base64
 
         local secret_key = "my-secret-key"
-        local timestamp = ngx_time()
+        local time = ngx_time()
+        local gmt = ngx_http_time(time)
         local access_key = "my-access-key"
         local custom_header_a = "asld$%dfasf"
         local custom_header_b = "23879fmsldfk"
         local signing_string = "GET" .. "/hello" ..  "" ..
-            access_key .. timestamp .. custom_header_a .. custom_header_b
+            access_key .. gmt .. custom_header_a .. custom_header_b
 
         local signature = hmac:new(secret_key, hmac.ALGOS.SHA256):final(signing_string)
         core.log.info("signature:", ngx_encode_base64(signature))
         local headers = {}
         headers["X-APISIX-HMAC-SIGNATURE"] = ngx_encode_base64(signature)
         headers["X-APISIX-HMAC-ALGORITHM"] = "hmac-sha256"
-        headers["X-APISIX-HMAC-TIMESTAMP"] = timestamp
+        headers["X-APISIX-DATE"] = gmt
         headers["X-APISIX-HMAC-ACCESS-KEY"] = access_key
         headers["X-APISIX-HMAC-SIGNED-HEADERS"] = "x-custom-header-a;x-custom-header-b"
         headers["x-custom-header-a"] = custom_header_a
@@ -323,23 +326,25 @@ passed
 
 
 
-=== TEST 11: verify: invalid timestamp
+=== TEST 11: verify: Clock skew exceeded
 --- config
 location /t {
     content_by_lua_block {
-        local ngx_time   = ngx.time
+        local ngx_time = ngx.time
+        local ngx_http_time = ngx.http_time
         local core = require("apisix.core")
         local t = require("lib.test_admin")
         local hmac = require("resty.hmac")
         local ngx_encode_base64 = ngx.encode_base64
 
         local secret_key = "my-secret-key2"
-        local timestamp = ngx_time()
+        local time = ngx_time()
+        local gmt = ngx_http_time(time)
         local access_key = "my-access-key2"
         local custom_header_a = "asld$%dfasf"
         local custom_header_b = "23879fmsldfk"
         local signing_string = "GET" .. "/hello" ..  "" ..
-            access_key .. timestamp .. custom_header_a .. custom_header_b
+            access_key .. gmt .. custom_header_a .. custom_header_b
 
         ngx.sleep(2)
 
@@ -348,7 +353,7 @@ location /t {
         local headers = {}
         headers["X-APISIX-HMAC-SIGNATURE"] = ngx_encode_base64(signature)
         headers["X-APISIX-HMAC-ALGORITHM"] = "hmac-sha256"
-        headers["X-APISIX-HMAC-TIMESTAMP"] = timestamp
+        headers["X-APISIX-DATE"] = gmt
         headers["X-APISIX-HMAC-ACCESS-KEY"] = access_key
 
         local code, body = t.test('/hello',
@@ -366,6 +371,6 @@ location /t {
 GET /t
 --- error_code: 401
 --- response_body eval
-qr/\{"message":"Invalid timestamp"\}/
+qr/\{"message":"Clock skew exceeded"\}/
 --- no_error_log
 [error]
diff --git a/t/plugin/hmac-auth.t b/t/plugin/hmac-auth.t
index dd584dc..efdf9f0 100644
--- a/t/plugin/hmac-auth.t
+++ b/t/plugin/hmac-auth.t
@@ -36,7 +36,8 @@ __DATA__
                     "plugins": {
                         "hmac-auth": {
                             "access_key": "my-access-key",
-                            "secret_key": "my-secret-key"
+                            "secret_key": "my-secret-key",
+                            "clock_skew": 10
                         }
                     }
                 }]],
@@ -49,7 +50,7 @@ __DATA__
                                     "access_key": "my-access-key",
                                     "secret_key": "my-secret-key",
                                     "algorithm": "hmac-sha256",
-                                    "clock_skew": 300
+                                    "clock_skew": 10
                                 }
                             }
                         }
@@ -246,7 +247,7 @@ GET /hello
 --- more_headers
 X-HMAC-SIGNATURE: asdf
 X-HMAC-ALGORITHM: hmac-sha256
-X-HMAC-TIMESTAMP: 112
+Date: Thu, 24 Sep 2020 06:39:52 GMT
 X-HMAC-ACCESS-KEY: sdf
 --- error_code: 401
 --- response_body
@@ -262,7 +263,7 @@ GET /hello
 --- more_headers
 X-HMAC-SIGNATURE: asdf
 X-HMAC-ALGORITHM: ljlj
-X-HMAC-TIMESTAMP: 112
+Date: Thu, 24 Sep 2020 06:39:52 GMT
 X-HMAC-ACCESS-KEY: my-access-key
 --- error_code: 401
 --- response_body
@@ -272,27 +273,59 @@ X-HMAC-ACCESS-KEY: my-access-key
 
 
 
-=== TEST 10: verify: invalid timestamp
+=== TEST 10: verify: Clock skew exceeded
 --- request
 GET /hello
 --- more_headers
 X-HMAC-SIGNATURE: asdf
 X-HMAC-ALGORITHM: hmac-sha256
-X-HMAC-TIMESTAMP: 112
+Date: Thu, 24 Sep 2020 06:39:52 GMT
 X-HMAC-ACCESS-KEY: my-access-key
 --- error_code: 401
 --- response_body
-{"message":"Invalid timestamp"}
+{"message":"Clock skew exceeded"}
 --- no_error_log
 [error]
 
 
 
-=== TEST 11: verify: ok
+=== TEST 11: verify: missing Date
+--- request
+GET /hello
+--- more_headers
+X-HMAC-SIGNATURE: asdf
+X-HMAC-ALGORITHM: hmac-sha256
+X-HMAC-ACCESS-KEY: my-access-key
+--- error_code: 401
+--- response_body
+{"message":"Invalid GMT format time"}
+--- no_error_log
+[error]
+
+
+
+=== TEST 12: verify: Invalid GMT format time
+--- request
+GET /hello
+--- more_headers
+X-HMAC-SIGNATURE: asdf
+X-HMAC-ALGORITHM: hmac-sha256
+Date: adfsdf
+X-HMAC-ACCESS-KEY: my-access-key
+--- error_code: 401
+--- response_body
+{"message":"Invalid GMT format time"}
+--- no_error_log
+[error]
+
+
+
+=== TEST 13: verify: ok
 --- config
 location /t {
     content_by_lua_block {
         local ngx_time   = ngx.time
+        local ngx_http_time = ngx.http_time
         local core = require("apisix.core")
         local t = require("lib.test_admin")
         local hmac = require("resty.hmac")
@@ -300,19 +333,20 @@ location /t {
 
         local secret_key = "my-secret-key"
         local timestamp = ngx_time()
+        local gmt = ngx_http_time(timestamp)
         local access_key = "my-access-key"
         local custom_header_a = "asld$%dfasf"
         local custom_header_b = "23879fmsldfk"
 
         local signing_string = "GET" .. "/hello" ..  "" ..
-            access_key .. timestamp .. custom_header_a .. custom_header_b
+            access_key .. gmt .. custom_header_a .. custom_header_b
 
         local signature = hmac:new(secret_key, hmac.ALGOS.SHA256):final(signing_string)
         core.log.info("signature:", ngx_encode_base64(signature))
         local headers = {}
         headers["X-HMAC-SIGNATURE"] = ngx_encode_base64(signature)
         headers["X-HMAC-ALGORITHM"] = "hmac-sha256"
-        headers["X-HMAC-TIMESTAMP"] = timestamp
+        headers["Date"] = gmt
         headers["X-HMAC-ACCESS-KEY"] = access_key
         headers["X-HMAC-SIGNED-HEADERS"] = "x-custom-header-a;x-custom-header-b"
         headers["x-custom-header-a"] = custom_header_a
@@ -338,7 +372,7 @@ passed
 
 
 
-=== TEST 12: add consumer with 0 clock skew
+=== TEST 14: add consumer with 0 clock skew
 --- config
     location /t {
         content_by_lua_block {
@@ -386,13 +420,13 @@ passed
 
 
 
-=== TEST 13: verify: invalid signature
+=== TEST 15: verify: invalid signature
 --- request
 GET /hello
 --- more_headers
 X-HMAC-SIGNATURE: asdf
 X-HMAC-ALGORITHM: hmac-sha256
-X-HMAC-TIMESTAMP: 112
+Date: Thu, 24 Sep 2020 06:39:52 GMT
 X-HMAC-ACCESS-KEY: my-access-key3
 --- error_code: 401
 --- response_body
@@ -402,7 +436,7 @@ X-HMAC-ACCESS-KEY: my-access-key3
 
 
 
-=== TEST 14: add consumer with 1 clock skew
+=== TEST 16: add consumer with 1 clock skew
 --- config
     location /t {
         content_by_lua_block {
@@ -450,11 +484,12 @@ passed
 
 
 
-=== TEST 15: verify: invalid timestamp
+=== TEST 17: verify: Invalid GMT format time
 --- config
 location /t {
     content_by_lua_block {
         local ngx_time   = ngx.time
+        local ngx_http_time = ngx.http_time
         local core = require("apisix.core")
         local t = require("lib.test_admin")
         local hmac = require("resty.hmac")
@@ -462,6 +497,7 @@ location /t {
 
         local secret_key = "my-secret-key2"
         local timestamp = ngx_time()
+        local gmt = ngx_http_time(timestamp)
         local access_key = "my-access-key2"
         local custom_header_a = "asld$%dfasf"
         local custom_header_b = "23879fmsldfk"
@@ -469,14 +505,14 @@ location /t {
         ngx.sleep(2)
 
         local signing_string = "GET" .. "/hello" ..  "" ..
-            access_key .. timestamp .. custom_header_a .. custom_header_b
+            access_key .. gmt .. custom_header_a .. custom_header_b
 
         local signature = hmac:new(secret_key, hmac.ALGOS.SHA256):final(signing_string)
         core.log.info("signature:", ngx_encode_base64(signature))
         local headers = {}
         headers["X-HMAC-SIGNATURE"] = ngx_encode_base64(signature)
         headers["X-HMAC-ALGORITHM"] = "hmac-sha256"
-        headers["X-HMAC-TIMESTAMP"] = timestamp
+        headers["Date"] = gmt
         headers["X-HMAC-ACCESS-KEY"] = access_key
         headers["X-HMAC-SIGNED-HEADERS"] = "x-custom-header-a;x-custom-header-b"
         headers["x-custom-header-a"] = custom_header_a
@@ -497,17 +533,18 @@ location /t {
 GET /t
 --- error_code: 401
 --- response_body eval
-qr/\{"message":"Invalid timestamp"\}/
+qr/\{"message":"Clock skew exceeded"\}/
 --- no_error_log
 [error]
 
 
 
-=== TEST 16: verify: put ok
+=== TEST 18: verify: put ok
 --- config
 location /t {
     content_by_lua_block {
-        local ngx_time   = ngx.time
+        local ngx_time = ngx.time
+        local ngx_http_time = ngx.http_time
         local core = require("apisix.core")
         local t = require("lib.test_admin")
         local hmac = require("resty.hmac")
@@ -519,19 +556,20 @@ location /t {
 
         local secret_key = "my-secret-key"
         local timestamp = ngx_time()
+        local gmt = ngx_http_time(timestamp)
         local access_key = "my-access-key"
         local custom_header_a = "asld$%dfasf"
         local custom_header_b = "23879fmsldfk"
 
         local signing_string = "PUT" .. "/hello" ..  "" ..
-            access_key .. timestamp .. custom_header_a .. custom_header_b
+            access_key .. gmt .. custom_header_a .. custom_header_b
 
         local signature = hmac:new(secret_key, hmac.ALGOS.SHA256):final(signing_string)
         core.log.info("signature:", ngx_encode_base64(signature))
         local headers = {}
         headers["X-HMAC-SIGNATURE"] = ngx_encode_base64(signature)
         headers["X-HMAC-ALGORITHM"] = "hmac-sha256"
-        headers["X-HMAC-TIMESTAMP"] = timestamp
+        headers["Date"] = gmt
         headers["X-HMAC-ACCESS-KEY"] = access_key
         headers["X-HMAC-SIGNED-HEADERS"] = "x-custom-header-a;x-custom-header-b"
         headers["x-custom-header-a"] = custom_header_a
@@ -557,11 +595,12 @@ passed
 
 
 
-=== TEST 17: verify: put ok (pass auth data by header `Authorization`)
+=== TEST 19: verify: put ok (pass auth data by header `Authorization`)
 --- config
 location /t {
     content_by_lua_block {
         local ngx_time   = ngx.time
+        local ngx_http_time   = ngx.http_time
         local core = require("apisix.core")
         local t = require("lib.test_admin")
         local hmac = require("resty.hmac")
@@ -573,17 +612,18 @@ location /t {
 
         local secret_key = "my-secret-key"
         local timestamp = ngx_time()
+        local gmt = ngx_http_time(timestamp)
         local access_key = "my-access-key"
         local custom_header_a = "asld$%dfasf"
         local custom_header_b = "23879fmsldfk"
 
         local signing_string = "PUT" .. "/hello" ..  "" ..
-            access_key .. timestamp .. custom_header_a .. custom_header_b
+            access_key .. gmt .. custom_header_a .. custom_header_b
         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-v2#" .. access_key .. "#" .. ngx_encode_base64(signature) .. "#" ..
-        "hmac-sha256#" .. timestamp .. "#x-custom-header-a;x-custom-header-b"
+        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
@@ -610,7 +650,7 @@ passed
 
 
 
-=== TEST 18: hit route without auth info
+=== TEST 20: hit route without auth info
 --- request
 GET /hello
 --- error_code: 401
@@ -621,7 +661,7 @@ GET /hello
 
 
 
-=== TEST 19: add consumer with signed_headers
+=== TEST 21: add consumer with signed_headers
 --- config
     location /t {
         content_by_lua_block {
@@ -647,7 +687,7 @@ GET /hello
                                     "access_key": "my-access-key5",
                                     "secret_key": "my-secret-key5",
                                     "algorithm": "hmac-sha256",
-                                    "clock_skew": 300,
+                                    "clock_skew": 0,
                                     "signed_headers": ["x-custom-header-a", "x-custom-header-b"]
                                 }
                             }
@@ -670,11 +710,12 @@ passed
 
 
 
-=== TEST 20: verify with invalid signed header
+=== TEST 22: verify with invalid signed header
 --- config
 location /t {
     content_by_lua_block {
         local ngx_time   = ngx.time
+        local ngx_http_time = ngx.http_time
         local core = require("apisix.core")
         local t = require("lib.test_admin")
         local hmac = require("resty.hmac")
@@ -682,19 +723,20 @@ location /t {
 
         local secret_key = "my-secret-key5"
         local timestamp = ngx_time()
+        local gmt = ngx_http_time(timestamp)
         local access_key = "my-access-key5"
         local custom_header_a = "asld$%dfasf"
         local custom_header_c = "23879fmsldfk"
 
         local signing_string = "GET" .. "/hello" ..  "" ..
-            access_key .. timestamp .. custom_header_a .. custom_header_c
+            access_key .. gmt .. custom_header_a .. custom_header_c
 
         local signature = hmac:new(secret_key, hmac.ALGOS.SHA256):final(signing_string)
         core.log.info("signature:", ngx_encode_base64(signature))
         local headers = {}
         headers["X-HMAC-SIGNATURE"] = ngx_encode_base64(signature)
         headers["X-HMAC-ALGORITHM"] = "hmac-sha256"
-        headers["X-HMAC-TIMESTAMP"] = timestamp
+        headers["Date"] = gmt
         headers["X-HMAC-ACCESS-KEY"] = access_key
         headers["X-HMAC-SIGNED-HEADERS"] = "x-custom-header-a;x-custom-header-c"
         headers["x-custom-header-a"] = custom_header_a
@@ -721,11 +763,12 @@ qr/\{"message":"Invalid signed header x-custom-header-c"\}/
 
 
 
-=== TEST 21: verify ok with signed headers
+=== TEST 23: verify ok with signed headers
 --- config
 location /t {
     content_by_lua_block {
-        local ngx_time   = ngx.time
+        local ngx_time = ngx.time
+        local ngx_http_time = ngx.http_time
         local core = require("apisix.core")
         local t = require("lib.test_admin")
         local hmac = require("resty.hmac")
@@ -733,18 +776,19 @@ location /t {
 
         local secret_key = "my-secret-key5"
         local timestamp = ngx_time()
+        local gmt = ngx_http_time(timestamp)
         local access_key = "my-access-key5"
         local custom_header_a = "asld$%dfasf"
 
         local signing_string = "GET" .. "/hello" ..  "" ..
-            access_key .. timestamp .. custom_header_a
+            access_key .. gmt .. custom_header_a
 
         local signature = hmac:new(secret_key, hmac.ALGOS.SHA256):final(signing_string)
         core.log.info("signature:", ngx_encode_base64(signature))
         local headers = {}
         headers["X-HMAC-SIGNATURE"] = ngx_encode_base64(signature)
         headers["X-HMAC-ALGORITHM"] = "hmac-sha256"
-        headers["X-HMAC-TIMESTAMP"] = timestamp
+        headers["date"] = gmt
         headers["X-HMAC-ACCESS-KEY"] = access_key
         headers["X-HMAC-SIGNED-HEADERS"] = "x-custom-header-a"
         headers["x-custom-header-a"] = custom_header_a