Note:
If you use an SDK provided by Alibaba Cloud, you do not need to follow this signature mechanism. SDKs are available for Java, PHP, and C#.
The API supports requests that are submitted using the GET and POST methods. However, the StringToSign is different for GET and POST requests.
Direct Mail authenticates every access request. Therefore, you must include signature information in every request, regardless of whether you use the HTTP or HTTPS protocol. Direct Mail uses symmetric encryption with an AccessKey ID and an AccessKey secret to verify the identity of the request sender. The AccessKey ID and AccessKey secret are part of the AccessKey information issued by Alibaba Cloud. You can view and manage your AccessKey information in the User Information Management section of the Alibaba Cloud Management Console. The AccessKey ID identifies the requester. The AccessKey secret is the key that is used to encrypt the signature string and to verify the signature on the server. You must keep your AccessKey information strictly confidential.
Signature steps
To sign a request, perform the following steps:
Create a canonicalized query string from the request parameters.
a. Sort the parameters.
Sort all request parameters, including common and API-specific parameters, in alphabetical order by name. The Signature parameter is not included in the signing process.
Note: For GET requests, these parameters are the part of the request URL that follows the
?and are separated by&.b. Encode the name and value of each request parameter.
URL-encode the parameter names and values using the UTF-8 character set. The URL encoding rules are as follows:
Do not encode the characters A-Z, a-z, 0-9, or the special characters
-,_,., and~.Encode other characters into the
%XYformat.XYrepresents the hexadecimal value of the character's ASCII code. For example, a double quotation mark (") is encoded as%22.Encode extended UTF-8 characters into the
%XY%ZA…format.A space must be encoded as
%20, not a plus sign (+).
Important: Libraries that support URL encoding, such as
java.net.URLEncoderin Java, typically encode based on the rules for theapplication/x-www-form-urlencodedMultipurpose Internet Mail Extensions (MIME) type. If you use these libraries for encoding, you must replace+with%20,*with%2A, and%7Ewith~after encoding to create a string that complies with the preceding rules.c. Use an equal sign (
=) to connect the encoded parameter name and its value.d. Use an ampersand (
&) to connect the encoded request parameters in the order from step a. The result is the canonicalized query string.Use the canonicalized query string from the previous step to create the string-to-sign in the following format:
StringToSign= HTTPMethod + "&" + percentEncode("/") + "&" + percentEncode(CanonicalizedQueryString)HTTPMethod is the HTTP method that is used to submit the request, such as GET or POST.
percentEncode("/") is the value that is obtained by encoding the
/character based on the URL encoding rules described in step 1.b. The value is%2F.percentEncode(CanonicalizedQueryString) is the string that is obtained by encoding the canonicalized query string from step 1 based on the URL encoding rules in step 1.b. Note: The result of percentEncode(CanonicalizedQueryString) is double-encoded.
Calculate the Hash-based Message Authentication Code (HMAC) value.
Calculate the HMAC value for the StringToSign from step 2 as defined in RFC2104.
Note: When you calculate the signature, the key is your AccessKeySecret followed by an ampersand (
&) character (ASCII code 38). The hash algorithm is SHA1.Calculate the signature value.
Encode the HMAC value from step 3 into a string using Base64 encoding. The result is the signature value (Signature).
Add the resulting signature value to the request parameters as the Signature parameter. This completes the request signing process.
Note: When you submit the signature value to the Direct Mail server as a request parameter, it must be URL-encoded in the same way as other parameters, based on the rules in RFC3986.
Signature example
This example shows how to call the SingleSendMail API by sending a POST request over HTTPS.
The request URL is http://dm.aliyuncs.com/.
The request parameters are as follows:
AccessKeyId=testid&AccountName=<a%b'>&Action=SingleSendMail&AddressType=1&Format=XML&HtmlBody=4&RegionId=cn-hangzhou&ReplyToAddress=true&SignatureMethod=HMAC-SHA1&SignatureNonce=c1b2c332-4cfb-4a0f-b8cc-ebe622aa0a5c&SignatureVersion=1.0&Subject=3&TagName=2&Timestamp=2016-10-20T06:27:56Z&ToAddress=1@test.com&Version=2015-11-23The StringToSign is as follows:
POST&%2F&AccessKeyId%3Dtestid%26AccountName%3D%253Ca%2525b%2527%253E%26Action%3DSingleSendMail%26AddressType%3D1%26Format%3DXML%26HtmlBody%3D4%26RegionId%3Dcn-hangzhou%26ReplyToAddress%3Dtrue%26SignatureMethod%3DHMAC-SHA1%26SignatureNonce%3Dc1b2c332-4cfb-4a0f-b8cc-ebe622aa0a5c%26SignatureVersion%3D1.0%26Subject%3D3%26TagName%3D2%26Timestamp%3D2016-10-20T06%253A27%253A56Z%26ToAddress%3D1%2540test.com%26Version%3D2015-11-23If the AccessKeyId is testid and the AccessKeySecret is testsecret, the key for calculating the HMAC is testsecret&. The calculated signature value is as follows:
llJfXJjBW3OacrVgxxsITgYaYm0=After signing, the parameters in the body of the POST request to http://dm.aliyuncs.com/ are as follows. The Signature parameter is added, and the Content-Type request header is changed to `application/x-www-form-urlencoded`:
Signature=llJfXJjBW3OacrVgxxsITgYaYm0=&AccessKeyId=testid&AccountName=<a%b'>&Action=SingleSendMail&AddressType=1&Format=XML&HtmlBody=4&RegionId=cn-hangzhou&ReplyToAddress=true&SignatureMethod=HMAC-SHA1&SignatureNonce=c1b2c332-4cfb-4a0f-b8cc-ebe622aa0a5c&SignatureVersion=1.0&Subject=3&TagName=2&Timestamp=2016-10-20T06:27:56Z&ToAddress=1@test.com&Version=2015-11-23The preceding code shows the required parameters for the request body before encoding. These parameters must be encoded before you send the actual request..
Code examples
Java
private static final String MAC_NAME ="HmacSHA1";
private static final String ENCODING ="UTF-8";
/**
* Signs encryptText using the HMAC-SHA1 method.
*
*@param encryptText The string to be signed.
*@param encryptKey The key.
*@return
*@throws Exception
*/
public static byte[] HmacSHA1Encrypt(StringencryptText, String encryptKey) throwsException {
byte[] data = encryptKey.getBytes(ENCODING);
// Creates a key from the given byte array. The second parameter specifies the name of the key algorithm.
SecretKey secretKey = new SecretKeySpec(data,MAC_NAME);
// Generates a Mac object for the specified Mac algorithm.
Mac mac = Mac.getInstance(MAC_NAME);
// Initializes the Mac object with the given key.
mac.init(secretKey);
byte[] text = encryptText.getBytes(ENCODING);
// Completes the Mac operation.
return mac.doFinal(text);
}
@Test
public void test() throws Exception {
/*StringToSign=
HTTPMethod + “&” +
percentEncode(“/”) + ”&” +
percentEncode(CanonicalizedQueryString)*/
String str ="AccessKeyId=testid&AccountName=<a%b'>&Action=SingleSendMail&AddressType=1&Format=XML&HtmlBody=4&RegionId=cn-hangzhou&ReplyToAddress=true&SignatureMethod=HMAC"+
"-SHA1&SignatureNonce=c1b2c332-4cfb-4a0f-b8cc-ebe622aa0a5c&SignatureVersion=1.0&Subject=3&TagName=2&Timestamp=2016-10-20T06:27:56Z&ToAddress=1@test.com&Version=2015-11-23";
String percentStr = "";
String[] strs = str.split("&");
for (int i = 0; i < strs.length;i++) {
String[] str1 =strs[i].split("=");
if (str1.length == 1){
percentStr = percentStr + getUtf8Encoder(str1[0])+ "=" + getUtf8Encoder("")+ "&";
}else {
percentStr = percentStr + getUtf8Encoder(str1[0])+ "=" + getUtf8Encoder(str1[1]) + "&";
}
}
percentStr =percentStr.substring(0,percentStr.lastIndexOf("&"));
String percent = URLEncoder.encode("/","UTF-8");
percentStr = getUtf8Encoder(percentStr);
String toSign = HttpMethod.POST + "&"+ percent +"&" + percentStr;
System.out.println("--------------"+ toSign);
/*POST&%2F&AccessKeyId%3Dtestid%26AccountName%3D%253Ca%2525b%2527%253E%26Action%3DSingleSendMail%26AddressType%3D1%26Format%3DXML%26HtmlBody%3D4%26RegionId%3Dcn-hangzhou%26ReplyToAddress%3Dtrue%26SignatureMethod%3DHMAC-SHA1%26SignatureNonce%3Dc1b2c332-4cfb-4a0f-b8cc-ebe622aa0a5c%26SignatureVersion%3D1.0%26Subject%3D3%26TagName%3D2%26Timestamp%3D2016-10-20T06%253A27%253A56Z%26ToAddress%3D1%2540test.com%26Version%3D2015-11-23*/
byte[] bytes = HmacSHA1Encrypt(toSign,"testsecret&");
String base64Str = Base64.encode(bytes);
System.out.println(base64Str);//llJfXJjBW3OacrVgxxsITgYaYm0=
}
private String getUtf8Encoder(String param) throwsUnsupportedEncodingException {
return URLEncoder.encode(param, "UTF-8")
.replaceAll("\\+","%20")
.replaceAll("\\*","%2A")
.replaceAll("%7E","~");
};Python
import hmac
import base64
# Replace StringToSign with the actual content.
message = b'StringToSign'
key = b'testsecret&'
h = hmac.new(key, message, digestmod='sha1')
# print(h.digest())
print(base64.b64encode(h.digest()))PHP
<?php
function encryptTokey($data){
$apikey = 'testsecret&';
$sign = base64_encode(hash_hmac("sha1", $data, $apikey, true));
//printf($sign);
return $sign;
}
// Replace StringToSign with the actual content.
echo encryptTokey(StringToSign);
?>FAQ
If you intermittently receive the SignatureDoesNotMatch error when you use the API, this error occurs because special characters in the encoded string were not replaced. For more information, see the Important section above.
If you cannot resolve a signature mismatch issue or are unsure how to use the signature mechanism, see the Request example. You can replace the parameters in the example with your own.