すべてのプロダクト
Search
ドキュメントセンター

IoT Platform:署名メカニズム

最終更新日:Aug 21, 2026

IoT Platform は、各 API リクエストの送信者を認証します。したがって、HTTP または HTTPS プロトコルを使用するすべての API リクエストに署名を含める必要があります。

署名方法

リクエストに署名するには、コンソールの 「アクセスキー管理」 ページに移動して、Alibaba Cloud アカウントの AccessKey ID と AccessKey Secret を取得します。これらを使用して、メッセージ認証コード (MAC) を生成できます。AccessKey ID はユーザーを識別します。AccessKey Secret は、署名文字列を暗号化し、サーバーが署名文字列を検証するために使用されるキーです。AccessKey Secret は、機密情報として厳重に管理する必要があります。

説明

IoT Platform は、Java、Python、PHP などの言語に対応したサーバーサイドのソフトウェア開発キット (SDK) を提供しています。これらの SDK を使用すると、署名プロセスを手動で実行する必要がなくなります。各 SDK の使用方法については、「サーバーサイド SDK (オリジナル)」および「サーバーサイド SDK (アップグレード)」をご参照ください。

リクエストに署名するには、次の手順を実行します。

  1. リクエストパラメーターから正規化されたクエリ文字列を構築します。

    1. パラメーターをソートします。

      リクエストパラメーターをパラメーター名でアルファベット順にソートします。これらのパラメーターには、共通リクエストパラメーターと API のカスタムパラメーターが含まれます。Signature パラメーター自体は含めないでください。

      説明

      GET メソッドを使用してリクエストを送信する場合、これらのパラメーターはリクエスト URL の ? の後に続く部分であり、& で区切られます。

    2. 各リクエストパラメーターの名前と値を URL エンコードします。

      RFC 3986 のルールに従って、UTF-8 文字セットを使用してパラメーターの名前と値をエンコードします。エンコードのルールは次のとおりです。

      • A~Z、a~z、0~9 の文字、および-_.~ はエンコードされません。

      • その他の文字は %XY 形式でエンコードされます。ここで、XY は文字の ASCII コードの 16 進値を表します。たとえば、二重引用符 (") は%22 としてエンコードされます。

      • 拡張 UTF-8 文字は %XY%ZA… 形式でエンコードされます。

      • スペースは、プラス記号 (+) の代わりに%20 としてエンコードする必要があります。

      このエンコード方法は、application/x-www-form-urlencoded MIME (Multipurpose Internet Mail Extensions) タイプのエンコードアルゴリズムと似ていますが、同じではありません。

      Java 標準ライブラリの java.net.URLEncoder を使用する場合、まず percentEncode メソッドを使用して文字列をエンコードできます。次に、エンコードされた文字列内のプラス記号 (+) を%20 に、アスタリスク (*) を%2A に、%7E をチルダ (~) に置き換えます。これにより、前述のルールに準拠したエンコード済み文字列が生成されます。

      private static final String ENCODING = "UTF-8";
      private static String percentEncode(String value) throws UnsupportedEncodingException {
      return value != null ? URLEncoder.encode(value, ENCODING).replace("+", "%20").replace("*", "%2A").replace("%7E", "~") : null;
      }
    3. エンコードされたパラメーター名とその値を等号 (=) で連結します。

    4. パラメーターと値のペアをパラメーター名でアルファベット順にソートし、& 記号を使用して連結します。

    これらの手順を完了すると、正規化されたクエリ文字列を取得できます。

  2. 署名対象の文字列を構築します。

    ステップ 1 の正規化されたクエリ文字列を percentEncode で処理して、署名対象の文字列を作成します。文字列は、以下の形式にする必要があります。

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

    パラメーターの説明:

    • HTTPMethod:リクエストの送信に使用される HTTP メソッド (GET など)。

    • percentEncode("/"):スラッシュ (/) の UTF-8 エンコード値である「%2F」。

    • percentEncode(CanonicalizedQueryString):パーセントエンコーディングされた正規化済みクエリ文字列。

  3. HMAC 値を計算します。

    RFC 2104 で定義されている HMAC-SHA1 アルゴリズムと、ステップ 2 で作成した StringToSign 文字列を使用して、HMAC 値を計算します。

    HMAC-SHA1(AccessKeySecret + "&", UTF-8-Encoding-Of(StringToSign))
    重要

    署名計算のキーは、AccessKeySecret の後ろにアンパサンド (&) 文字 (ASCII コード 38) を付けたものです。ハッシュアルゴリズムは SHA1 です。

  4. 署名値を計算します。

    Base64 エンコーディングのルールを使用して、ステップ 3 で取得した HMAC 値を文字列にエンコードします。生成された文字列が署名値 (Signature) です。

    Signature = Base64(HMAC-SHA1(AccessKeySecret + "&", UTF-8-Encoding-Of(StringToSign)))
  5. 署名を追加します。

    Signature パラメーターをリクエストパラメーターに追加します。このパラメーターの値は、生成された署名です。この署名は、RFC 3986 の規定に従って URL エンコードする必要があります。

署名の例

この例では、Pub API の呼び出し方法を示します。この例では、パラメーター値として AccessKeyId=testidAccessKeySecret=testsecretProductKey=12345abcdeTopicFullName=/12345abcde/testdevice/user/getMessageContent=aGVsbG8gd29ybGQ、およびQos=0 を仮定します。

  1. 署名前のリクエスト URL を構築します。

    http://iot.cn-shanghai.aliyuncs.com/?Action=Pub&MessageContent=aGVsbG8gd29ybGQ&Timestamp=2018-07-31T07:43:57Z&SignatureVersion=1.0&Format=XML&Qos=0&SignatureNonce=3ee8c1b8-83d3-44af-a94f-4e0ad82fd6cf&Version=2018-01-20&AccessKeyId=testid&SignatureMethod=HMAC-SHA1&RegionId=cn-shanghai&ProductKey=12345abcde&TopicFullName=/12345abcde/testdevice/user/get
  2. 署名対象の文字列 StringToSign を計算します。

    GET&%2F&AccessKeyId%3Dtestid%26Action%3DPub%26Format%3DXML%26MessageContent%3DaGVsbG8gd29ybGQ%26ProductKey%3D12345abcde%26Qos%3D0%26RegionId%3Dcn-shanghai%26SignatureMethod%3DHMAC-SHA1%26SignatureNonce%3D3ee8c1b8-83d3-44af-a94f-4e0ad82fd6cf%26SignatureVersion%3D1.0%26Timestamp%3D2018-07-31T07%3A43%3A57Z%26TopicFullName%3D%252F12345abcde%252Ftestdevice%252Fuser%252Fget%26Version%3D2018-01-20
  3. 署名値を計算します。

    AccessKeySecrettestsecret であるため、計算に使用されるキーはtestsecret& です。計算された署名値は次のとおりです。

    NUh3otvAoXOZmG/a2gDShh6Ze9w=
  4. 署名を Signature パラメーターとしてリクエスト URL に追加します。最終的な URL は次のとおりです。

    http://iot.cn-shanghai.aliyuncs.com/?MessageContent=aGVsbG8gd29ybGQ&Action=Pub&Timestamp=2018-07-31T07%3A43%3A57Z&SignatureVersion=1.0&Format=XML&Qos=0&SignatureNonce=3ee8c1b8-83d3-44af-a94f-4e0ad82fd6cf&Version=2018-01-20&AccessKeyId=testid&Signature=NUh3otvAoXOZmG%2Fa2gDShh6Ze9w%3D&SignatureMethod=HMAC-SHA1&RegionId=cn-shanghai&ProductKey=12345abcde&TopicFullName=%2F12345abcde%2Ftestdevice%2Fuser%2Fget

Java コード例

次の Java コードは、署名を作成する方法の例です。

  1. Maven プロジェクトの依存関係を追加します。

    <!-- Apache Commons Lang 3.x -->
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.12.0</version> <!-- 最新バージョンを使用 -->
    </dependency>
    
    <!-- Apache Commons Codec -->
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-codec</artifactId>
        <version>1.15</version> <!-- 最新バージョンを使用 -->
    </dependency>
  2. Config.java の内容は次のとおりです。

    /*   
     * Copyright  2018 Alibaba. All rights reserved.
     */
    package com.aliyun.iot.demo.sign;
    
    /**
     * サーバーサイド API 署名用の設定ファイル
     * 
     * @author: ali
     * @version: 0.1 2018-08-08 08:23:54
     */
    public class Config {
    
        // AccessKey 情報
        public static String accessKey = "123456******3456";
        public static String accessKeySecret = "123456******34567******4567890";
    
        public final static String CHARSET_UTF8 = "UTF-8";
    }

    パラメーター

    説明

    accessKey

    123456**3456

    IoT Platform コンソールにログインします。プロフィール画像にポインターを合わせ、[アクセスキー管理] をクリックして、AccessKey ID と AccessKey Secret を取得します。

    説明

    Resource Access Management (RAM) ユーザーを使用する場合、RAM ユーザーに IoT Platform (AliyunIOTFullAccess) を管理する権限を付与する必要があります。そうしないと、接続は失敗します。権限を付与する方法の詳細については、「RAM ユーザーへの IoT Platform へのアクセス権限の付与」をご参照ください。

    accessKeySecret

    123456**34567**4567890

  3. UrlUtil.java の内容は次のとおりです。

    /*   
     * Copyright  2018 Alibaba. All rights reserved.
     */
    package com.aliyun.iot.demo.sign;
    
    import java.net.URLEncoder;
    import java.util.Map;
    
    import org.apache.commons.lang3.StringUtils;
    
    /**
     * URL 処理クラス
     * 
     * @author: ali
     * @version: 0.1 2018-06-21 20:40:52
     */
    public class UrlUtil {
    
        private final static String CHARSET_UTF8 = "UTF-8";
    
        public static String urlEncode(String url) {
            if (!StringUtils.isEmpty(url)) {
                try {
                    url = URLEncoder.encode(url, "UTF-8");
                } catch (Exception e) {
                    System.out.println("URL encode error:" + e.getMessage());
                }
            }
            return url;
        }
    
        public static String generateQueryString(Map<String, String> params, boolean isEncodeKV) {
            StringBuilder canonicalizedQueryString = new StringBuilder();
            for (Map.Entry<String, String> entry : params.entrySet()) {
                if (isEncodeKV)
                    canonicalizedQueryString.append(percentEncode(entry.getKey())).append("=")
                            .append(percentEncode(entry.getValue())).append("&");
                else
                    canonicalizedQueryString.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
            }
            if (canonicalizedQueryString.length() > 1) {
                canonicalizedQueryString.setLength(canonicalizedQueryString.length() - 1);
            }
            return canonicalizedQueryString.toString();
        }
    
        public static String percentEncode(String value) {
            try {
                // URLEncoder.encode でエンコードした後、API エンコード仕様を満たすために「+」、「*」、「%7E」を置き換えます。
                return value == null ? null
                        : URLEncoder.encode(value, CHARSET_UTF8).replace("+", "%20").replace("*", "%2A").replace("%7E",
                                "~");
            } catch (Exception e) {
    
            }
            return "";
        }
    }
  4. SignatureUtils.java の内容は次のとおりです。

    /*   
     * Copyright  2018 Alibaba. All rights reserved.
     */
    package com.aliyun.iot.demo.sign;
    
    import java.io.IOException;
    import java.io.UnsupportedEncodingException;
    import java.net.URI;
    import java.net.URISyntaxException;
    import java.net.URLDecoder;
    import java.net.URLEncoder;
    import java.util.Map;
    import java.util.TreeMap;
    
    import javax.crypto.Mac;
    import javax.crypto.spec.SecretKeySpec;
    
    import org.apache.commons.codec.binary.Base64;
    import org.apache.commons.lang3.StringUtils;
    
    /**
     * サーバーサイド API 署名
     * 
     * @author: ali
     * @version: 0.1 2018-06-21 20:47:05
     */
    public class SignatureUtils {
    
        private final static String CHARSET_UTF8 = "UTF-8";
        private final static String ALGORITHM = "HmacSHA1";
        private final static String SEPARATOR = "&";
    
        public static Map<String, String> splitQueryString(String url)
                throws URISyntaxException, UnsupportedEncodingException {
            URI uri = new URI(url);
            String query = uri.getQuery();
            final String[] pairs = query.split("&");
            TreeMap<String, String> queryMap = new TreeMap<String, String>();
            for (String pair : pairs) {
                final int idx = pair.indexOf("=");
                final String key = idx > 0 ? pair.substring(0, idx) : pair;
                if (!queryMap.containsKey(key)) {
                    queryMap.put(key, URLDecoder.decode(pair.substring(idx + 1), CHARSET_UTF8));
                }
            }
            return queryMap;
        }
    
        public static String generate(String method, Map<String, String> parameter, String accessKeySecret)
                throws Exception {
            String signString = generateSignString(method, parameter);
            System.out.println("signString---" + signString);
            byte[] signBytes = hmacSHA1Signature(accessKeySecret + "&", signString);
            String signature = newStringByBase64(signBytes);
            System.out.println("signature----" + signature);
            if ("POST".equals(method))
                return signature;
            return URLEncoder.encode(signature, "UTF-8");
        }
    
        public static String generateSignString(String httpMethod, Map<String, String> parameter) throws IOException {
            TreeMap<String, String> sortParameter = new TreeMap<String, String>();
            sortParameter.putAll(parameter);
            String canonicalizedQueryString = UrlUtil.generateQueryString(sortParameter, true);
            if (null == httpMethod) {
                throw new RuntimeException("httpMethod can not be empty");
            }
            StringBuilder stringToSign = new StringBuilder();
            stringToSign.append(httpMethod).append(SEPARATOR);
            stringToSign.append(percentEncode("/")).append(SEPARATOR);
            stringToSign.append(percentEncode(canonicalizedQueryString));
            return stringToSign.toString();
        }
    
        public static String percentEncode(String value) {
            try {
                return value == null ? null
                        : URLEncoder.encode(value, CHARSET_UTF8).replace("+", "%20").replace("*", "%2A").replace("%7E",
                                "~");
            } catch (Exception e) {
            }
            return "";
        }
    
        public static byte[] hmacSHA1Signature(String secret, String baseString) throws Exception {
            if (StringUtils.isEmpty(secret)) {
                throw new IOException("secret can not be empty");
            }
            if (StringUtils.isEmpty(baseString)) {
                return null;
            }
            Mac mac = Mac.getInstance("HmacSHA1");
            SecretKeySpec keySpec = new SecretKeySpec(secret.getBytes(CHARSET_UTF8), ALGORITHM);
            mac.init(keySpec);
            return mac.doFinal(baseString.getBytes(CHARSET_UTF8));
        }
    
        public static String newStringByBase64(byte[] bytes) throws UnsupportedEncodingException {
            if (bytes == null || bytes.length == 0) {
                return null;
            }
            return new String(Base64.encodeBase64(bytes, false), CHARSET_UTF8);
        }
    }
  5. メインエントリファイル Main.java を作成します。

    /*   
     * Copyright  2018 Alibaba. All rights reserved.
     */
    package com.aliyun.iot.demo.sign;
    
    import java.io.UnsupportedEncodingException;
    import java.net.URLEncoder;
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * 署名ツールのメインエントリ
     * 
     * @author: ali
     * @version: 0.1 2018-09-18 15:06:48
     */
    public class Main {
    
        // 1. Config.java の AccessKey 情報を変更します。
        // 2. 方法 2 を推奨します。 すべてのパラメーターを指定する必要があります。
        // 3. 「Final signature」は最終的な署名結果です。
        public static void main(String[] args) throws UnsupportedEncodingException {
    
            // 方法 1
            System.out.println("Method 1:");
            String str = "GET&%2F&AccessKeyId%3D" + Config.accessKey
                    + "%26Action%3DRegisterDevice%26DeviceName%3D1533023037%26Format%3DJSON%26ProductKey%3DaxxxUtgaRLB%26RegionId%3Dcn-shanghai%26SignatureMethod%3DHMAC-SHA1%26SignatureNonce%3D1533023037%26SignatureVersion%3D1.0%26Timestamp%3D2018-07-31T07%3A43%3A57Z%26Version%3D2018-01-20";
            byte[] signBytes;
            try {
                signBytes = SignatureUtils.hmacSHA1Signature(Config.accessKeySecret + "&", str.toString());
                String signature = SignatureUtils.newStringByBase64(signBytes);
                System.out.println("signString---" + str);
                System.out.println("signature----" + signature);
                System.out.println("Final signature: " + URLEncoder.encode(signature, Config.CHARSET_UTF8));
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println();
    
            // 方法 2
            System.out.println("Method 2:");
            Map<String, String> map = new HashMap<String, String>();
            // 共通パラメーター
            map.put("Format", "JSON");
            map.put("Version", "2018-01-20");
            map.put("AccessKeyId", Config.accessKey);
            map.put("SignatureMethod", "HMAC-SHA1");
            map.put("Timestamp", "2018-07-31T07:43:57Z");
            map.put("SignatureVersion", "1.0");
            map.put("SignatureNonce", "1533023037");
            map.put("RegionId", "cn-shanghai");
            // リクエストパラメーター
            map.put("Action", "RegisterDevice");
            map.put("DeviceName", "1533023037");
            map.put("ProductKey", "axxxUtgaRLB");
            try {
                String signature = SignatureUtils.generate("GET", map, Config.accessKeySecret);
                System.out.println("Final signature: " + signature);
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println();
        }
    }