注意:
SDK を使用する場合、署名は不要です。現在、Java、PHP、および C# SDK が提供されています。
インターフェイスは GET リクエストと POST リクエストをサポートしていますが、GET リクエストと POST リクエストの StringToSign は異なります。
DirectMail サービスは、各アクセスリクエストに対して送信者認証を実行します。そのため、リクエストの送信に HTTP プロトコルまたは HTTPS プロトコルを使用するかにかかわらず、リクエストには署名情報を含める必要があります。DirectMail は、AccessKeyId と AccessKeySecret を使用してリクエスト送信者を認証するために対称暗号化を実行します。 AccessKeyId と AccessKeySecret は、Alibaba Cloud によってビジターに正式に発行されます(ビジターは Alibaba Cloud 公式 Web サイトで申請および管理できます)。 AccessKeyId はビジターの ID を示します。 AccessKeySecret は、署名文字列を暗号化し、サーバー上で署名文字列を検証するための秘密鍵です。 AccessKeySecret は機密性を厳守し、Alibaba Cloud と認証されたビジターのみが知っている必要があります。
手順
アクセスリクエストに署名するには、次の方法を使用します。
1. リクエストパラメーターを使用して正規化されたクエリ文字列を構築します。
a. すべてのリクエストパラメーター(このドキュメントで説明されている特定のリクエストインターフェイスのパブリックリクエストパラメーターとカスタムパラメーターを含むが、パブリックリクエストパラメーターで言及されている Signature パラメーターを除く)をパラメーター名でアルファベット順に並べ替えます。
注意: GET メソッドを使用してリクエストを送信する場合、これらのパラメーターはリクエスト URI のパラメーターセクション(つまり、URI 内の ?
に続く &
で接続されたセクション)を構成します。
b. 各リクエストパラメーターの名前と値がエンコードされます。名前と値は、UTF-8 文字セットで URL エンコーディングを採用する必要があります。 URL エンコーディングルールは次のとおりです。
文字 A-Z、a-z、0-9、
-
、_
、.
、および~
はエンコードされません。その他の文字は
%XY
形式でエンコードされ、XY は 16 進表記の文字の ASCII コードを表します。たとえば、英語の二重引用符"
は%22
としてエンコードされます。拡張 UTF-8 文字は
%XY%ZA...
形式でエンコードされます。英語のスペースは、プラス記号
+
ではなく%20
としてエンコードされます。
注意: 一般的に、URL エンコーディングをサポートするライブラリ(Java の java.net.URLEncoder
など)はすべて、application/x-www-form-urlencoded
MIME タイプのルールに従ってエンコードされます。このエンコーディング方法は実装中に直接適用できます。つまり、エンコードされた文字列のプラス記号 +
を %20
に、アスタリスク *
を %2A
に置き換え、%7E
をチルダ ~
に戻してエンコーディングルールに準拠させます。
c. エンコードされたパラメーター名と値を英語の等号 =
で接続します。
d. 等号で接続されたパラメーター名と値のペアを、アンパサンド &
でアルファベット順に接続して、正規化されたクエリ文字列を作成します。
2. 前の手順で構築した正規化されたクエリ文字列を使用して、次のルールに従って署名計算用の文字列を構築します。
StringToSign=
HTTPMethod + "&" +
percentEncode("/") + "&" +
percentEncode(CanonicalizedQueryString)
ここで、HTTPMethod はリクエスト送信に使用される HTTP メソッドです(例: GET または POST)。
percentEncode("/") は、URL エンコーディングルールに従って文字 /
のエンコードされた値、つまり %2F
です。
percentEncode(CanonicalizedQueryString) は、手順 1 で構築された正規化されたクエリ文字列のエンコードされた文字列であり、URL エンコーディングルールによって生成されます。
3. RFC2104 の定義に基づいて、署名文字列を使用して署名の HMAC 値を計算します。
注意: 署名計算に使用されるキーは、末尾に「&」文字(ASCII:38)が追加された AccessKeySecret であり、SHA1 ハッシュアルゴリズムが使用されます。
4. Base64 エンコーディングルールに基づいて HMAC 値を文字列にエンコードすると、署名値(Signature)を取得できます。
5. 取得した署名値を Signature パラメーターとしてリクエストパラメーターに追加します。リクエスト署名プロセスは完了です。
注意: 署名値が最終的なリクエストパラメーター値として DirectMail サーバーに送信される前に、他のパラメーターの場合と同様に、RFC3986 ルールに基づいて、取得した署名値に対して URL エンコーディングを実装する必要があります。
例
HTTPS 経由で SingleSendMail インターフェイスを呼び出すための POST リクエストを送信する例を取り上げます。
リクエスト URL は https://dm.aliyuncs.com/ です。
パラメーターは次のとおりです。
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
したがって、StringToSign は次のとおりです。
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
AccessKeyId が testid
、AccessKeySecret が testsecret
、HMAC 計算に使用されるキーが testsecret&
であると仮定すると、計算された署名値は次のとおりです。
llJfXJjBW3OacrVgxxsITgYaYm0=
https://dm.aliyuncs.com/ からの署名付き POST リクエストの本文コンテンツ。
注意: 追加された Signature パラメーターとリクエストヘッダー 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
上記の パラメーターは、コーディング前に BODY に必要です。特定のリクエストでは、パラメーターをコーディングする必要があります。 サンプル署名リクエスト (Java) をご参照ください。
次のコードは参考用です。
private static final String MAC_NAME ="HmacSHA1";
private static final String ENCODING ="UTF-8";
/**
* HMAC-SHA1 を使用して encryptText を暗号化します
*
*@param encryptText 暗号化する文字列
*@param encryptKey 秘密鍵
*@return
*@throws Exception
*/
public static byte[] HmacSHA1Encrypt(String encryptText, String encryptKey) throws Exception {
byte[] data = encryptKey.getBytes(ENCODING);
//指定されたバイト数に従って秘密鍵を構築し、2 番目のパラメーターはキー計算の名前を指定します。
SecretKey secretKey = new SecretKeySpec(data, MAC_NAME);
//MAC 計算オブジェクトを生成します。
Mac mac = Mac.getInstance(MAC_NAME);
//指定された秘密鍵で MAC オブジェクトを初期化します。
mac.init(secretKey);
byte[] text = encryptText.getBytes(ENCODING);
//MAC 計算を完了します。
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 は対応するコンテンツに置き換える必要があります。
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 は対応するコンテンツに置き換える必要があります。
echo encryptTokey(StringToSign);
?>
署名の FAQ:
API の使用時に良好な状況と悪い状況があり、エラー SignatureDoesNotMatch が表示される場合、理由: エンコードされた文字列が特殊文字に置き換えられていません。詳細は上記の特別な注意事項をご参照ください。署名不一致の問題が解決しない場合、または署名メカニズムの使用方法が不明な場合は、リクエスト例に移動し、独自のリクエストパラメーターに直接置き換えることをお勧めします。