hmac-auth

This Plugin works with a object and a consumer of your API has to add its key to the request header for verification.

First we enable the Plugin on a Consumer object as shown below:

You can also use the APISIX Dashboard to complete the operation through a web UI.

Next, you can configure the Plugin to a Route or a Service:

  1. curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
  2. {
  3. "uri": "/index.html",
  4. "plugins": {
  5. "hmac-auth": {}
  6. },
  7. "upstream": {
  8. "type": "roundrobin",
  9. "nodes": {
  10. "127.0.0.1:1980": 1
  11. }
  12. }
  13. }'

The formula for calculating the signature is signature = HMAC-SHAx-HEX(secret_key, signing_string).

In order to generate the signature, two parameters, secret_key and signing_string are required. The secret_key is configured by a Consumer and the signing_string is calculated as signing_string = HTTP Method + \n + HTTP URI + \n + canonical_query_string + \n + access_key + \n + Date + \n + signed_headers_string. If any of the terms are missing, they are replaced by an empty string. The different terms in this calculation are explained below:

  • HTTP Method : HTTP request method in uppercase. For example, GET, PUT, POST etc.
  • HTTP URI : HTTP URI. Should start with “/“ and “/“ denotes an empty path.
  • Date : Date in the HTTP header in GMT format.
  • canonical_query_string : The result of encoding the query string in the URL (the string “key1 = value1 & key2 = value2” after the “?” in the URL).
  • signed_headers_string : Concatenation of the specified request headers.
  1. Extract the query terms from the URL.
  2. Split the query terms into key-value pairs by using & as the separator.
  3. If encode_uri_params is true:
    1. If there are only keys, the conversion formula is uri_encode(key) + "=".
    2. If there are both keys and values, the conversion formula is uri_encode(key) + "=" + uri_encode(value). Here, the value can even be an empty string.
    3. Sort by key in lexicographic order and connect them with & symbol to generate the corresponding canonical_query_string.
  4. If encode_uri_params is false:
    1. If there are both keys and values, the conversion formula is key + "=" + value. Here, the value can even be an empty string.
    2. Sort by key in lexicographic order and connect them with & symbol to generate the corresponding canonical_query_string.

And the algorithm for generating the is as follows:

  1. Obtain the specified headers to add to the calculation from the request header.
  2. Splice the specified headers in name:value format. This is the signed_headers_string.
  1. HeaderKey1 + ":" + HeaderValue1 + "\n"\+
  2. HeaderKey2 + ":" + HeaderValue2 + "\n"\+
  3. ...
  4. HeaderKeyN + ":" + HeaderValueN + "\n"

The example below shows signature string splicing:

  1. curl -i http://127.0.0.1:9080/index.html?name=james&age=36 \
  2. -H "X-HMAC-SIGNED-HEADERS: User-Agent;x-custom-a" \
  3. -H "x-custom-a: test" \
  4. -H "User-Agent: curl/7.29.0"

The signing_string generated according to the algorithm above is:

  1. "GET
  2. /index.html
  3. age=36&name=james
  4. user-key
  5. Tue, 19 Jan 2021 11:33:20 GMT
  6. User-Agent:curl/7.29.0
  7. x-custom-a:test
  8. "

The last request header also needs + \n.

The Python code below shows how to generate the signature:

TypeHash
SIGNATURE8XV1GB7Tq23OJcoz6wjqTs4ZLxr9DiLoY4PxzScWGYg=

You can also refer to for how to generate signatures for different programming languages.

  1. X-HMAC-DIGEST: base64(hmac-sha(<body>))

If there is no request body, you can set the X-HMAC-DIGEST value to the HMAC-SHA of an empty string.

note

To calculate the digest of the request body, the Plugin will load the body to memory which can cause high memory consumption if the body is large. To avoid this, you can limit the max allowed body size by configuring max_req_body (default 512KB). Request bodies larger than the set size will be rejected.

You can now use the generated signature to make requests as shown below:

  1. curl -i "http://127.0.0.1:9080/index.html?name=james&age=36" \
  2. -H "X-HMAC-SIGNATURE: 8XV1GB7Tq23OJcoz6wjqTs4ZLxr9DiLoY4PxzScWGYg=" \
  3. -H "X-HMAC-ALGORITHM: hmac-sha256" \
  4. -H "X-HMAC-ACCESS-KEY: user-key" \
  5. -H "Date: Tue, 19 Jan 2021 11:33:20 GMT" \
  6. -H "X-HMAC-SIGNED-HEADERS: User-Agent;x-custom-a" \
  7. -H "x-custom-a: test" \
  8. -H "User-Agent: curl/7.29.0"
  1. HTTP/1.1 200 OK
  2. Content-Type: text/html; charset=utf-8
  3. Transfer-Encoding: chunked
  4. Connection: keep-alive
  5. Date: Tue, 19 Jan 2021 11:33:20 GMT
  6. Server: APISIX/2.2
  7. ......

The signature can be put in the header of the request:

    Or, the signature can be placed separately in another request header:

    1. 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
    1. HTTP/1.1 200 OK
    2. Content-Type: text/html
    3. Content-Length: 13175
    4. ...
    5. Accept-Ranges: bytes
    6. <!DOCTYPE html>
    7. <html lang="cn">
    hmac-auth - 图2note
    1. If there are multiple signed headers, they must be separated by ;. For example, x-custom-header-a;x-custom-header-b.
    2. SIGNATURE needs to be base64 encoded for encryption.

    You can use custom header keys for the auth parameters by changing the plugin_attr in your configuration file (conf/config.yaml):

    1. plugin_attr:
    2. hmac-auth:
    3. signature_key: X-APISIX-HMAC-SIGNATURE
    4. algorithm_key: X-APISIX-HMAC-ALGORITHM
    5. date_key: X-APISIX-DATE
    6. access_key: X-APISIX-HMAC-ACCESS-KEY
    7. signed_headers_key: X-APISIX-HMAC-SIGNED-HEADERS
    8. body_digest_key: X-APISIX-HMAC-BODY-DIGEST
    1. curl http://127.0.0.1:9080/index.html \
    2. -H 'X-APISIX-HMAC-SIGNATURE: base64_encode(SIGNATURE)' \
    3. -H 'X-APISIX-HMAC-ALGORITHM: ALGORITHM' \
    4. -H 'X-APISIX-DATE: DATE' \
    5. -H 'X-APISIX-HMAC-ACCESS-KEY: ACCESS_KEY' \
    6. -H 'X-APISIX-HMAC-SIGNED-HEADERS: SIGNED_HEADERS' \
    7. -H 'X-APISIX-HMAC-BODY-DIGEST: BODY_DIGEST' -i

    To disable the hmac-auth Plugin, you can delete the corresponding JSON configuration from the Plugin configuration. APISIX will automatically reload and you do not have to restart for this to take effect.

    1. curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
    2. {
    3. "uri": "/index.html",
    4. "plugins": {},
    5. "upstream": {
    6. "type": "roundrobin",
    7. "nodes": {
    8. "127.0.0.1:1980": 1
    9. }
    10. }