To call a published API that uses the digest authentication method (AppKey and AppSecret), the client must use the signature key pair to calculate the signature for the requested content, and then transmit the signature to the server for verification. The SDKs for API Gateway are integrated with the signature mechanism. After the signature key pair is configured in the SDKs, you can initiate a request that carries the correct signature. This topic describes how to calculate signatures on the client.
1. Principle of signature and signature verification
API Gateway provides the signature and signature verification functions, which are used to:
- Check the validity of requests received from clients to ensure that the requests contain the correct signature that is generated based on the authorized AppKey.
- Prevent the requested data from being tampered with during transmission.
The API provider can create an app on the APPs page of the API Gateway console. Each app carries a signature key pair consisting of AppKey and AppSecret. After the API provider authorizes the app to use the API, the API caller can use the signature key pair to call the API. Note that the app can be issued by the API provider or owned by the API caller.
When the client calls the API, it must use the authorized signature key pair to encrypt and sign key data in the request, and includes the AppKey and the signature string in the header of the request transmitted to API Gateway. After receiving the request, API Gateway reads the AppKey from the request header, obtains the AppSecret that corresponds to the AppKey, uses the AppSecret to calculate the signature of key data in the received request, and compares the calculated signature with that received from the client to verify the signature. Only requests that pass signature verification are sent to backend services. If API Gateway determines that a request is invalid, it returns an error.
API Gateway verifies only signatures contained in API requests that use the following security certification methods: Alibaba Cloud APP and OpenID Connect & Alibaba Cloud APP.
The API caller has obtained the signature key pair assigned to the related API before calling the API.
- APP Key
- APP Secret
The called API uses the following security certification methods: Alibaba Cloud APP and OpenID Connect & Alibaba Cloud APP.
1.2 Signature generation on the client
The client generates a signature in three steps:
- Extract key data from the original request to obtain a signature string.
- Use the encryption algorithm and AppSecret to encrypt the signature string to obtain the signature.
- Add headers related to the signature to the original HTTP request to obtain the final HTTP request.
1.3 Signature verification on the server
The server verifies the signature received from the client in four steps:
- Extract key data from the request to obtain the signature string.
- Read the AppKey from the request and use the AppKey to obtain the AppSecret.
- Use the encryption algorithm and AppSecret to encrypt the signature string to obtain the signature.
- Read the client-side signature from the request and compare the server-side signature with the client-side signature.
2. Signature generation and transfer
2.1 Extract the signature string
The client must extract key data from the HTTP requests and combine the data into a signature string. The signature string is in the following format:
HTTPMethod Accept Content-MD5 Content-Type Date Headers PathAndParameters
The preceding seven fields constitute a signature string and are separated with \n. If the Headers field is left empty, \n is not required. If the other fields are left empty, \n must be retained. The signature is case-sensitive. Data extraction for each field follows these rules:
- HTTPMethod: the HTTP method used to send a request, such as POST. The field value is in uppercase.
- Accept: the value of the Accept header in the request, which can be left empty. We recommend that the Accept header be explicitly displayed in the request. If the Accept header is empty, some HTTP clients will use the default value */* for Accept, causing signature verification to fail.
- Content-MD5: the value of the Content-MD5 header in a request. This field can be left empty. The value is calculated only when a request contains a body that is not of the Form type. The following example shows how to calculate the value of the Content-MD5 header by using Java:
String content-MD5 = Base64.encodeBase64(MD5(bodyStream.getbytes("UTF-8")));
- Content-Type: the value of the Content-Type header, which can be left empty.
- Date: the value of the Date header in the request, which can be left empty.
- Headers: You can specify the headers for signature calculation. The following rules apply when you concatenate signature strings:
- Header keys are first sorted in alphabetical order and then concatenated in the following way:
HeaderKey1 + ":" + HeaderValue1 + "\n"\+ HeaderKey2 + ":" + HeaderValue2 + "\n"\+ ... HeaderKeyN + ":" + HeaderValueN + "\n"
- If the value of a header is empty, use HeaderKey + ":" + "\n" for signature and retain the header key and colon.
- The header keys used for signature calculation are separated with commas (,) and placed in headers whose key is X-Ca-Signature-Headers.
- The following headers are not used for signature calculation: X-Ca-Signature, X-Ca-Signature-Headers, Accept, Content-MD5, Content-Type, and Date.
- The PathAndParameters field contains all the parameters of the path, query, and form types.
Path + "?" + Key1 + "=" + Value1 + "&" + Key2 + "=" + Value2 + ... "&" + KeyN + "=" + ValueN
- Keys of query and form parameters are first sorted in alphabetical order and then concatenated by using the preceding method.
- If the query and form parameters are left empty, you can use path parameters without the need to add the question mark (?).
- If the parameter value is empty, only the key is used for signature calculation.
- If query and form parameters have array parameters (parameters with the same key but different values), the first value is used for signature calculation.
The following example shows parameters in a common HTTP request:
POST /http2test/test? param1=test HTTP/1.1 host:api.aliyun.com accept:application/json; charset=utf-8 ca_version:1 content-type:application/x-www-form-urlencoded; charset=utf-8 x-ca-timestamp:1525872629832 date:Wed, 09 May 2018 13:30:29 GMT+00:00 user-agent:ALIYUN-ANDROID-DEMO x-ca-nonce:c9f15cbf-f4ac-4a6c-b54d-f51abf4b5b44 content-length:33 username=xiaoming&password=123456789
The following example shows a correct signature string:
POST application/json; charset=utf-8 application/x-www-form-urlencoded; charset=utf-8 Wed, 09 May 2018 13:30:29 GMT+00:00 x-ca-key:203753385 x-ca-nonce:c9f15cbf-f4ac-4a6c-b54d-f51abf4b5b44 x-ca-signature-method:HmacSHA256 x-ca-timestamp:1525872629832 /http2test/test? param1=test&password=123456789&username=xiaoming
2.2 Signature calculation
After the client combines key data extracted from the HTTP request into a signature string, it must encrypt and encode the signature string to generate the final signature. API Gateway supports the following encryption algorithms:
The following example shows the encryption method. stringToSign is the extracted signature string and secret is the AppSecret.
Mac hmacSha256 = Mac.getInstance("HmacSHA256"); hmacSha256.init(new SecretKeySpec(secret.getBytes("UTF-8"), 0, keyBytes.length, "HmacSHA256")); byte md5Result = hmacSha1.doFinal(stringToSign.getBytes("UTF-8")); String sign = Base64.encodeBase64String(md5Result);
Mac hmacSha1 = Mac.getInstance("HmacSHA1"); hmacSha1.init(new SecretKeySpec(secret.getBytes("UTF-8"), 0, keyBytes.length, "HmacSHA1")); byte md5Result = hmacSha1.doFinal(stringToSign.getBytes("UTF-8")); String sign = Base64.encodeBase64String(md5Result);
First, a Byte array is obtained after StringToSign is UTF-8-decoded. The Byte array is then encrypted and Base64-encoded to generate the final signature.
2.3 Signature transfer
The client must include the following four headers in the requests sent to API Gateway for signature verification:
- x-ca-key: the AppKey, which is required.
- x-ca-signature-method: the signature method, which is optional. Valid values: HmacSHA256 and HmacSHA1. Default value: HmacSHA256.
- X-Ca-Signature-Headers: The keys of all signature headers. Separate multiple keys with commas (,). This parameter is optional.
- X-Ca-Signature: the signature, which is required.
The following example shows an HTTP request with a signature:
POST /http2test/test? param1=test HTTP/1.1 host:api.aliyun.com accept:application/json; charset=utf-8 ca_version:1 content-type:application/x-www-form-urlencoded; charset=utf-8 x-ca-timestamp:1525872629832 date:Wed, 09 May 2018 13:30:29 GMT+00:00 user-agent:ALIYUN-ANDROID-DEMO x-ca-nonce:c9f15cbf-f4ac-4a6c-b54d-f51abf4b5b44 x-ca-key:203753385 x-ca-signature-method:HmacSHA256 x-ca-signature-headers:x-ca-timestamp,x-ca-key,x-ca-nonce,x-ca-signature-method x-ca-signature:xfX+bZxY2yl7EB/qdoDy9v/uscw3Nnj1pgoU+Bm6xdM= content-length:33 username=xiaoming&password=123456789
3. Signature troubleshooting
If signature verification fails, API Gateway contains the signature string (StringToSign) of the server in the header of the HTTP response that is returned to the client. The key is X-Ca-Error-Message. You can find out errors by comparing the signature string (StringToSign) calculated on the client side with the signature string returned by the server.
If the two values are the same, check the AppSecret that is used for signature calculation.
HTTP headers do not support line breaks. Line breaks in stringToSign are replaced with number signs (#).
errorMessage: Invalid Signature, Server StringToSign:`GET#application/json##application/json##X-Ca-Key:200000#X-Ca-Timestamp:1589458000000#/app/v1/config/keys? keys=TEST`
The following example shows the signature on the server side:
GET application/json application/json X-Ca-Key:200000 X-Ca-Timestamp:1589458000000 /app/v1/config/keys? keys=TEST
4. Example of using Java for signature
For more information about signature calculation, see SDKs provided by API Gateway. You can download Java, Android, and Objective-C SDKs with source code on the following pages of the API Gateway console:
- Publish APIs - Owned APIs SDK Auto-Generation
- Consume APIs - Authorized APIs SDK Auto-Generation
For signature calculation by using Java and Android, see the class com.alibaba.cloudapi.sdk.util.SignUtil.