All Products
Search
Document Center

Direct Mail:Signature

Last Updated:Sep 27, 2023

Note:

  • If SDK is used, signature is not required. Currently, Java, PHP, and C# SDKs have been provided.

  • Interfaces support GET and POST requests, but the StringToSigns of a GET request and a POST request are different.

DirectMail service performs sender authentication for each access request. Therefore, whether HTTP or HTTPS protocol is used to submit a request, the request must contain the signature information. DirectMail performs symmetric encryption to authenticate the request sender using the AccessKeyId and AccessKeySecret. The AccessKeyId and AccessKeySecret are officially issued to visitors by Alibaba Cloud (visitors can apply for and manage them on the Alibaba Cloud official website). The AccessKeyId indicates the identity of the visitor. The AccessKeySecret is the secret key to encrypt the signature string and verify the signature string on the server. The AccessKeySecret must be kept strictly confidential and only be known to Alibaba Cloud and the authenticated visitor.

Procedure

The following method is used to sign the access request:

1. Construct Canonicalized Query String using the request parameters.

a. Order all the request parameters (including the public request parameters and custom parameters for the given request interfaces described in this document, but excluding the Signature parameter mentioned in public request parameters) alphabetically by parameter names.

Note: When a request is submitted using the GET method, these parameters constitute the parameter section of the request URI (that is, the section in the URI following ? and connected by &).

b. The name and value of each request parameter are encoded. The names and values must adopt URL encoding in the UTF-8 character set. The URL encoding rules are as follows:

  • The characters A-Z, a-z, 0-9, -, _, ., and ~ are not encoded;

  • Other characters are encoded in the %XY format, with XY representing the characters’ ASCII code in hexadecimal notation. For example, the English double quotes " are encoded as %22.

  • Extended UTF-8 characters are encoded in the %XY%ZA... format;

  • The English space is encoded as %20, rather than the plus sign +.

Note: Generally, libraries that support URL encoding (such as java.net.URLEncoder in Java) are all encoded following the rules for the application/x-www-form-urlencoded MIME type. This encoding method can apply directly during implementation, namely replacing the plus signs + in the encoded strings with %20, the asterisks * with %2A, and change %7E back to the tilde ~ to conform to the encoding rules.

c. Connect the encoded parameter names and values with the English equal sign =.

d. Connect the parameter name and value pairs connected by equal signs alphabetically with the ampersand & to produce the Canonicalized Query String.

2. Follow the following rules to construct the string for signature calculation using the Canonicalized Query String constructed in the previous step:

 StringToSign=
 HTTPMethod + "&" +
 percentEncode("/") + "&" +
 percentEncode(CanonicalizedQueryString)        

Here, HTTPMethod is the HTTP method used for request submission, for example, GET or POST.

percentEncode (“/“) is the encoded value for the character / according to the URL encoding rules, namely %2F.

percentEncode (CanonicalizedQueryString) is the encoded string of the Canonicalized Query String constructed in step 1, produced by the URL encoding rules.

3. Based on the RFC2104 definition, the signature string is used to calculate the signature’s HMAC value.

Note: The Key used for signature calculation is the AccessKeySecret with a “&” character (ASCII:38) added in the end, and the SHA1 hashing algorithm is used.

4. Encode the HMAC value into a string based on Base64 encoding rules, and you can get the signature value (Signature).

5. Add the obtained signature value to the request parameters as the Signature parameter. The request signing process is completed.

Note: URL encoding must be implemented for the obtained signature value based on the RFC3986 rule, like in the case of other parameters, before the signature value is submitted to the DirectMail server as the final request parameter value.

Example

Take sending a POST request for calling the SingleSendMail interface over HTTPS as an example.

The request URL is: https://dm.aliyuncs.com/.

The parameters are:

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

Therefore, the StringToSign is:

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

Suppose the AccessKeyId is testid, the AccessKeySecret is testsecret,and the Key used for HMAC calculation is testsecret&, then the calculated signature value is:

llJfXJjBW3OacrVgxxsITgYaYm0=

The body content of the signed POST request from https://dm.aliyuncs.com/ .

Note: the Signature parameter added and the change in the request header Content-Type: 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-23

The above parameters are required for BODY before coding. The specific request needs to code the parameters. Please refer to the Sample signature.

The following codes are for your reference.

private static final String MAC_NAME ="HmacSHA1";
private static final String ENCODING ="UTF-8";

/**
 * Use HMAC-SHA1 to encrypt the encryptText
 *
 *@param encryptText The string to be encrypted
 *@param encryptKey  The secret key
 *@return
 *@throws Exception
 */
public static byte[] HmacSHA1Encrypt(StringencryptText, String encryptKey) throwsException {
byte[] data = encryptKey.getBytes(ENCODING);
//Construct the secret key according to the specified bytes, and the second parameter specifies the name of the key calculation.
SecretKey secretKey = new SecretKeySpec(data,MAC_NAME);
//Generate a MAC calculation object.
Mac mac = Mac.getInstance(MAC_NAME);
//Initialize the MAC object by the specified secret key.
mac.init(secretKey);

byte[] text = encryptText.getBytes(ENCODING);
//Complete the MAC calculation.
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);

/*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) throws UnsupportedEncodingException {
return URLEncoder.encode(param, "UTF-8")
                .replaceAll("\\+","%20")
                .replaceAll("\\*","%2A")
                .replaceAll("%7E","~");
 };

Python:

import hmac
import base64
#StringToSign needs to be replaced with the corresponding 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;
}
//StringToSign needs to be replaced with the corresponding content.
echo encryptTokey(StringToSign);
?>

Signature FAQ:

If there are good and bad situations when using the API, the error SignatureDoesNotMatch is displayed. Reason: The encoded string is not replaced with special characters. Please refer to the above special precautions for details. If the problem of signature mismatch is not solved or it is unclear how to use the signature mechanism, it is recommended to move to the request example and directly replace it with your own request parameters.