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

Simple Log Service:リクエスト署名

最終更新日:Sep 15, 2026

すべての Simple Log Service (SLS) API リクエストでは、Alibaba Cloud の AccessKey ペアと HMAC-SHA1 署名を使用した署名ベースの認証が必要です。

注意事項

SLS SDK は署名を自動的に処理し、複数の言語をサポートしています。可能な場合は、手動署名の代わりに SDK を使用してください。詳細については、「Simple Log Service SDK の概要」をご参照ください。

セキュリティ検証プロセス:

  • リクエスターの識別。

    リクエスターは AccessKey ペアを使用してデジタル署名を生成します。SLS はこのペアをアイデンティティ検証とアクセス制御に使用します。

  • リクエストの改ざんの検出。

    SLS はサーバー側で署名を再計算し、クライアントから提供された署名と比較します。不一致はリクエストの改ざんを示し、リクエストは拒否されます。

署名には AccessKey ペアが必要です。AccessKey ペア。既存のペアを使用するか、新規に作成し、それが [有効] になっていることを確認してください。

以降のセクションでは、リクエストの構造、署名の計算、および署名コードのサンプルについて説明します。

リクエスト構造

次の表に、必須の HTTP ヘッダーフィールドを示します。値は、大文字と小文字を区別します。

フィールド

説明

例

x-log-signaturemethod

暗号化方式。

hmac-sha1

x-log-apiversion

API バージョン。

0.6.0

Date

RFC 822/1123 形式 (GMT) の標準 HTTP タイムスタンプ。形式: %a, %d %b %Y %H:%M:%S GMT。

Mon, 3 Jan 2010 08:33:47 GMT

Content-MD5

リクエストボディの MD5 ハッシュ。大文字の 16 進数文字列として表されます。

49DFDD54B01CBCD2D2AB5E9E5EE6B9B9

Authorization

リクエスト署名。形式: LOG accessKeyId:Signature。署名文字列の詳細については、「署名計算プロセス」をご参照ください。

LOG testAccessKeyId:RLETq4u7sWb3cssZIhsun****

Content-Type

HTTP リクエストボディのタイプ。リクエストにボディがない場合は、このフィールドを省略します。

application/json

署名付き HTTP リクエストの例:

POST /logstores/test-logstore/shards/0?action=split HTTP/1.1

Host: ali-test-project.cn-hangzhou.log.aliyuncs.com
Date: Tue, 23 Aug 2022 12:12:03 GMT
x-log-apiversion: 0.6.0
x-log-signaturemethod: hmac-sha1
Content-Length: 18
Content-Type: application/json
Content-MD5: 49DFDD54B01CBCD2D2AB5E9E5EE6B9B9
Authorization: LOG testAccessKeyId:RLETq4u7sWb3cssZIhsun****


{"hello": "world"}

署名計算プロセス

Authorization ヘッダーは LOG accessKeyId:Signature という形式を使用します。ここで、AccessKeyId はキー ID で、Signature は計算されたシグネチャ文字列です。このセクションでは、Signature 値の作成方法について説明します。

署名メッセージ

署名文字列は、署名メッセージを暗号化およびエンコードすることによって生成されます。次の図は、その作成プロセスを示しています。

image

パラメーター

説明

例

method

大文字の HTTP リクエストメソッド。有効な値:GET、POST、PUT、および DELETE。

GET

Content-MD5

リクエストボディの MD5 ハッシュ (大文字の 16 進数文字列)。ボディが存在しない場合は空の文字列。

49DFDD54B01CBCD2D2AB5E9E5EE6B9B9

Content-Type

HTTP リクエストボディのタイプ。ボディが存在しない場合は空の文字列。

application/json

Date

RFC 822/1123 形式 (GMT) の現在時刻。形式: %a, %d %b %Y %H:%M:%S GMT。

Mon, 3 Jan 2010 08:33:47 GMT

Header

プレフィックスが x-log- または x-acs- のヘッダーを、キーの昇順でソートしたもの。キーと値は コロン (:) で結合され、ペアは改行で区切られます。

  • x-log-apiversion:0.6.0

  • x-log-bodyrawsize:0

  • x-log-signaturemethod:hmac-sha1

Uri

リクエストパス。ドメイン名とクエリパラメーターは除きます。

/logstores/test-logstore

クエリパラメーター

キーの昇順でソートされたクエリパラメーター。= で結合され、& で区切られます。

offset=1&size=10

署名メッセージの例。最終行を除く各行は改行で終わります。

POST
49DFDD54B01CBCD2D2AB5E9E5EE6B9B9
application/json
Tue, 23 Aug 2022 12:12:03 GMT
x-log-apiversion:0.6.0
x-log-bodyrawsize:0
x-log-signaturemethod:hmac-sha1
/logstores?offset=1&size=10

署名文字列

署名文字列を計算するには:

  1. 署名メッセージを作成します。

  2. AccessKey Secret を使用して、HMAC-SHA1 でメッセージを暗号化します。

  3. 結果を Base64 エンコードして署名文字列を生成します。

例

次の例では、この AccessKey ペアを使用します:

AccessKeyId = "bq2sjzesjmo86kq****"
AccessKeySecret = "4fdO2fTDDnZPU/L7CHNd****"
  • 例 1

    GET リクエストを使用して、ali-test-project 内のすべての Logstore を一覧表示します。署名する HTTP リクエスト:

    GET /logstores?logstoreName=&offset=0&size=1000 HTTP/1.1
    Date: Mon, 09 Nov 2015 06:11:16 GMT
    Host: ali-test-project.cn-hangzhou.log.aliyuncs.com
    x-log-apiversion: 0.6.0
    x-log-bodyrawsize:0
    x-log-signaturemethod: hmac-sha1

    生成された署名メッセージ:

    GET
    
    
    Mon, 09 Nov 2015 06:11:16 GMT
    x-log-apiversion:0.6.0
    x-log-bodyrawsize:0
    x-log-signaturemethod:hmac-sha1
    /logstores?logstoreName=&offset=0&size=1000

    GET リクエストにはボディがないため、Content-MD5 と Content-Type は空の文字列になります。結果の署名:

    jEYOTCJs2e88o+y5F4/S5I****

    署名付き HTTP リクエスト:

    GET /logstores?logstoreName=&offset=0&size=1000 HTTP/1.1
    Date: Mon, 09 Nov 2015 06:11:16 GMT
    Host: ali-test-project.cn-hangzhou.log.aliyuncs.com
    x-log-apiversion: 0.6.0
    x-log-bodyrawsize:0
    x-log-signaturemethod: hmac-sha1
    Authorization: LOG bq2sjzesjmo86kq35behupbq:jEYOTCJs2e88o+y5F4/S5I****
  • 例 2

    ali-test-project の test-logstore に次のログを書き込みます:

    topic=""
    time=1447048976
    source="10.10.10.1"
    "TestKey": "TestContent"

    署名する HTTP リクエスト:

    POST /logstores/test-logstore HTTP/1.1
    Date: Mon, 09 Nov 2015 06:03:03 GMT
    Host: ali-test-project.cn-hangzhou.log.aliyuncs.com
    x-log-apiversion:0.6.0
    x-log-bodyrawsize:50
    x-log-compresstype:lz4
    x-log-signaturemethod:hmac-sha1
    Content-MD5: 1DD45FA4A70A9300CC9FE7305AF2C494
    Content-Length: 52
    <ログは Protobuf 形式のバイトストリームにシリアル化されます。>

    ログは Protocol Buffer (Protobuf) 形式でリクエストボディとしてシリアル化されます。Protobuf 形式の詳細については、「データエンコーディング」をご参照ください。Content-Type は application/x-protobuf で、Content-MD5 はボディの MD5 ハッシュです。生成された署名メッセージ:

    POST
    1DD45FA4A70A9300CC9FE7305AF2C494
    application/x-protobuf
    Mon, 09 Nov 2015 06:03:03 GMT
    x-log-apiversion:0.6.0
    x-log-bodyrawsize:50
    x-log-compresstype:lz4
    x-log-signaturemethod:hmac-sha1
    /logstores/test-logstore

    結果の署名:

    XWLGYHGg2F2hcfxWxMLiNk****

    署名付き HTTP リクエスト:

    POST /logstores/test-logstore HTTP/1.1
    Date: Mon, 09 Nov 2015 06:03:03 GMT
    Host: ali-test-project.cn-hangzhou.log.aliyuncs.com
    x-log-apiversion:0.6.0
    x-log-bodyrawsize:50
    x-log-compresstype:lz4
    x-log-signaturemethod:hmac-sha1
    Content-MD5: 1DD45FA4A70A9300CC9FE7305AF2C494
    Content-Length: 52
    
    Authorization: LOG bq2sjzesjmo86kq35behupbq:XWLGYHGg2F2hcfxWxMLiNk****
    <ログは Protobuf 形式のバイトストリームにシリアル化されます。>

サンプルコード

  • Java のサンプルコード

    この例では、 commons-codec ライブラリを使用します。次の依存関係を pom.xml に追加します:

    <dependency>
      <groupId>commons-codec</groupId>
      <artifactId>commons-codec</artifactId>
      <version>1.15</version>
    </dependency>

    署名の例:

    package com.aliyun.openservices.log.http.signer;
    
    import org.apache.commons.codec.binary.Base64;
    
    import javax.crypto.Mac;
    import javax.crypto.spec.SecretKeySpec;
    import java.math.BigInteger;
    import java.nio.charset.StandardCharsets;
    import java.security.MessageDigest;
    import java.text.DateFormat;
    import java.text.SimpleDateFormat;
    import java.util.*;
    import java.util.stream.Collectors;
    
    public class v1 {
        public static String md5(byte[] bs) throws Exception {
            MessageDigest digest = MessageDigest.getInstance("MD5");
            digest.update(bs);
            String hex = new BigInteger(1, digest.digest()).toString(16).toUpperCase();
            return new String(new char[32 - hex.length()]).replace("\0", "0") + hex;
        }
    
        public static String getDateString() {
            DateFormat df = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
            df.setTimeZone(new SimpleTimeZone(0, "GMT"));
            return df.format(new Date());
        }
    
        public static void sign(String method, String uri, String accessKeyId, String accessKeySecret,
                                Map<String, String> params,
                                Map<String, String> headers,
                                byte[] body) throws Exception {
    
            int contentLength = 0;
            String contentMD5 = "", message = "";
            headers.put("x-log-apiversion", "0.6.0");
            headers.put("x-log-signaturemethod", "hmac-sha1");
            if (body != null && body.length > 0) {
                contentLength = body.length;
                contentMD5 = md5(body);
                headers.put("Content-MD5", contentMD5);
            }
            String date = getDateString();
            headers.put("Date", date);
            headers.put("Content-Length", String.valueOf(contentLength));
    
            message += method + "\n"
                + contentMD5 + "\n"
                + headers.getOrDefault("Content-Type", "") + "\n"
                + date + "\n";
            // ヘッダー
            String headerStr = headers.entrySet().stream()
                .filter(e -> e.getKey().startsWith("x-log-") || e.getKey().startsWith("x-acs-"))
                .sorted(Map.Entry.comparingByKey())
                .map(e -> String.format("%s:%s\n", e.getKey(), e.getValue()))
                .collect(Collectors.joining(""));
            message += headerStr;
            // URI とパラメーター
            message += uri;
            if (params.size() > 0) {
                message += "?";
            }
            message += params.entrySet().stream()
                .sorted(Map.Entry.comparingByKey())
                .map(e -> String.format("%s=%s", e.getKey(), e.getValue()))
                .collect(Collectors.joining("&"));
            // 署名と認可
            Mac mac = Mac.getInstance("HmacSHA1");
            mac.init(new SecretKeySpec(accessKeySecret.getBytes(StandardCharsets.UTF_8), "HmacSHA1"));
            String signature = new String(Base64.encodeBase64(mac.doFinal(message.getBytes(StandardCharsets.UTF_8))));
            String auth = "LOG " + accessKeyId + ":" + signature;
            headers.put("Authorization", auth);
        }
    }
                                
  • Python のサンプルコード

    署名の例:

    import base64
    import hashlib
    import hmac
    import locale
    from datetime import datetime
    from typing import Dict, Tuple
    
    
    def get_date():
        try:
            locale.setlocale(locale.LC_TIME, "C")
        except Exception as ex:
            pass
        return datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')
    
    
    def sign(method: str, uri: str, access_key_id: str,
             access_key_secret: str, params: Dict[str, str],
             headers: Dict[str, str], body: bytes):
        content_length = 0
        content_md5, message = '', ''
        headers["x-log-apiversion"] = "0.6.0"
        headers["x-log-signaturemethod"] = "hmac-sha1"
        if body is not None and len(body) > 0:
            content_length = str(len(body))
            content_md5 = hashlib.md5(body).hexdigest().upper()
            headers['Content-MD5'] = content_md5
        date = get_date()
        headers['Date'] = date
        headers['Content-Length'] = content_length
        content_type = headers.get('Content-Type', '')
    
        message += method + "\n" + content_md5 + \
            "\n" + content_type + "\n" + date + "\n"
    
        # ヘッダー
        filter_by_prefix = lambda t: t[0].startswith('x-log-') or t[0].startswith('x-acs-')
        slsHeaders = list(filter(filter_by_prefix, headers.items()))
        sort_by_key = lambda k: k[0]
        for [k, v] in sorted(slsHeaders, key=sort_by_key):
            message += k + ':' + v + "\n"
        # URI とパラメーター
        message += uri
        message += '?' if len(params) > 0 else ''
        sep = ''
        for [k, v] in sorted(params.items(), key=sort_by_key):
            message += sep + k + '=' + v
            sep = '&'
        # 署名と認可
        hashed = hmac.new(access_key_secret.encode('utf8'),
                          message.encode('utf8'), hashlib.sha1).digest()
        signature = base64.encodebytes(hashed).decode('utf8').rstrip()
        auth = f'LOG {access_key_id}:{signature}'
        headers['Authorization'] = auth
                                
  • PHP のサンプルコード

    署名の例:

    <?php
    // 新しいヘッダー配列を返します
    function sign($method, $uri, $accessKeyId, $accessKeySecret, $params, $headers, $body)
    {
      $contentLength = 0;
      $headers["x-log-apiversion"] = "0.6.0";
      $headers["x-log-signaturemethod"] = "hmac-sha1";
      if (!is_null($body) && strlen($body) > 0) {
        $contentLength = strlen($body);
        $contentMd5 = strtoupper(md5($body));
        $headers["Content-MD5"] = $contentMd5;
      }
      // 日付
      setlocale(LC_TIME, 'en_US');
      $date = gmdate('D, d M Y H:i:s \G\M\T', time());
      $headers["Date"] = $date;
      $headers["Content-Length"] = (string)$contentLength;
      $contentType = isset($headers['Content-Type']) ? $headers['Content-Type'] : '';
      $message = $method . "\n" . $contentMd5 . "\n" . $contentType . "\n" . $date . "\n";
      // ヘッダー
      $filterHeaders = [];
      foreach ($headers as $key => $val) {
        if (str_starts_with($key, 'x-log-') || str_starts_with($key, 'x-acs-')) {
          $filterHeaders[$key] = $val;
        }
      }
      ksort($filterHeaders);
      foreach ($filterHeaders as $key => $val) {
        $message .= $key . ':' . $val . "\n";
      }
      // URI とパラメーター
      $message .= $uri;
      if (sizeof($params) > 0) {
        $message .= '?';
      }
      ksort($params);
      $sep = '';
      foreach ($params as $key => $val) {
        $message .= $sep . $key . '=' . $val;
        $sep = '&';
      }
      // 署名と認可
      $signature = base64_encode(hash_hmac('sha1', $message, $accessKeySecret, TRUE));
      $auth = 'LOG ' . $accessKeyId . ':' . $signature;
      $headers['Authorization'] = $auth;
      return $headers;
    };
    
    // 呼び出し例
    $headers = sign(
      'POST',
      '/logstores/test-logstore',
      'testAccessId',
      'testAccessKey',
      array(
        "test" => "test",
        "hello" => "world"
      ),
      array(
        "x-log-signaturemethod" => "hmac-sha1",
        "x-log-bodyrawsize" => "0",
        "x-log-apiversion" => "0.6.0"
      ),
      'hello, world'
    );
    echo ($headers['Authorization']);
    foreach ($headers as $key => $val) {
      echo ($key . '=' . $val . "\n");
    }
    ?>
  • Go のサンプルコード

    署名の例:

    package sls
    
    import (
        "crypto/hmac"
        "crypto/md5"
        "crypto/sha1"
        "encoding/base64"
        "fmt"
        "sort"
        "strconv"
        "strings"
        "time"
    )
    
    
    /*
    * @param uri http リクエストの URI。ホストとクエリパラメーターは除きます (例:/logstores/test-logstore)
    * @param headers この関数はヘッダーを変更します。ヘッダーは nil マップであってはなりません
    * @param method 大文字の Http メソッド (例:GET、POST、PUT、DELETE)
    */
    func Sign(method, uri, accessKeyID, accessKeySecret string, headers, queryParams map[string]string, body []byte) error {
        var message, signature string
        var contentMD5, contentType, date string
        headers["x-log-apiversion"] = "0.6.0";
        headers["x-log-signaturemethod"] = "hmac-sha1";
        if len(body) > 0 {
            contentMD5 = fmt.Sprintf("%X", md5.Sum(body))
            headers["Content-MD5"] = contentMD5
        }
    
        date = time.Now().In(time.FixedZone("GMT", 0)).Format(time.RFC1123)
        headers["Date"] = date
        headers["Content-Length"] = strconv.Itoa(len(body))
        if val, ok := headers["Content-Type"]; ok {
            contentType = val
        }
        message += method + "\n" + contentMD5 + "\n" + contentType + "\n" + date + "\n"
    
        // ヘッダー
        slsHeaders := make(map[string]string)
        for k, v := range headers {
            if strings.HasPrefix(k, "x-log-") || strings.HasPrefix(k, "x-acs-") {
                slsHeaders[k] = v
            }
        }
        forEachInOrder(slsHeaders, func(k, v string) {
            message += k + ":" + v + "\n"
        })
    
        message += uri
        if len(queryParams) > 0 {
            message += "?"
        }
        sep := ""
        forEachInOrder(queryParams, func(k, v string) {
            message += sep + k + "=" + v
            sep = "&"
        })
    
        // 署名 = base64(hmac-sha1(SignString の UTF8 エンコーディング, AccessKeySecret))
        mac := hmac.New(sha1.New, []byte(accessKeySecret))
        _, err := mac.Write([]byte(message))
        if err != nil {
            return err
        }
        signature = base64.StdEncoding.EncodeToString(mac.Sum(nil))
        auth := fmt.Sprintf("LOG %v:%v", accessKeyID, signature)
        headers["Authorization"] = auth
        return nil
    }
    
    
    func forEachInOrder(m map[string]string, f func(k, v string)) {
        var ss sort.StringSlice
        for k := range m {
            ss = append(ss, k)
        }
        ss.Sort()
        for _, k := range ss {
            f(k, m[k])
        }
    }
  • C# のサンプルコード

    署名の例:

    using System.Security.Cryptography;
    using System.Text;
    
    using StringMap = System.Collections.Generic.Dictionary<string, string>;
    
    void sign(string method, string uri,
    string accessKeyId, string accessKeySecret,
    StringMap queryParams,
    StringMap headers,
    byte[] body
    )
    {
      int contentLength = 0;
      string contentMd5 = "", message = "";
      headers["x-log-apiversion"] = "0.6.0";
      headers["x-log-signaturemethod"] = "hmac-sha1";
      if (body != null && body.Length > 0)
      {
        contentLength = body.Length;
        contentMd5 = BitConverter.ToString(MD5.Create().ComputeHash(body)).Replace("-", "");
        Console.WriteLine(contentMd5);
        headers["Content-MD5"] = contentMd5;
      }
      string date = DateTime.Now.ToUniversalTime().ToString("R");
      headers["Date"] = date;
      headers["Content-Length"] = contentLength.ToString();
    
      message += method + "\n"
      + contentMd5 + "\n"
      + headers.GetValueOrDefault("Content-Type", "") + "\n"
      + date + "\n";
    
      var sortedHeader = from entry in headers orderby entry.Key ascending select entry;
      // ヘッダー
      foreach (var entry in sortedHeader)
      {
        if (entry.Key.StartsWith("x-log-") || entry.Key.StartsWith("x-acs-"))
        {
          message += entry.Key + ":" + entry.Value + "\n";
        }
      }
      // URL とパラメーター
      message += uri;
      if (queryParams.Count() > 0)
      {
        message += "?";
      }
      var sortedParam = from entry in queryParams orderby entry.Key ascending select entry;
      string sep = "";
      foreach (var entry in sortedParam)
      {
        message += sep + entry.Key + "=" + entry.Value;
        sep = "&";
      }
      var hmac = new HMACSHA1(Encoding.ASCII.GetBytes(accessKeySecret));
      var signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(message)));
      var auth = "LOG " + accessKeyId + ":" + signature;
      headers["Authorization"] = auth;
    }
  • C++ のサンプルコード

    署名の例。要件に基づいてヘルパー関数を実装します。adapter.h ヘッダーファイルは Simple Log Service SDK for C++ に属しています。SDK を使用して署名することを推奨します。詳細については、「Simple Log Service SDK for C++ の概要」をご参照ください。

    • CodecTool::CalcMD5(string):MD5 ハッシュ値を計算し、その値を大文字を含む 16 進数文字列に変換します。

    • CodecTool::StartWith(string, string):ある文字列が別の文字列で始まるかどうかをチェックします。

    • CodecTool::Base64Encode(string):文字列を Base64 でエンコードします。

    • CodecTool::CalcHMACSHA1(string, string):HMAC-SHA1 アルゴリズムを使用してハッシュ値を計算します。

    • CodecTool::GetDateString():現在時刻のフォーマット済み文字列を取得します。形式: %a, %d %b %Y %H:%M:%S GMT。例:Mon,3 Jan 2010 08:33:47 GMT。

    #include <map>
    #include <string>
    #include <unordered_map>
    #include <unordered_set>
    #include <vector>
    
    #include "adapter.h"
    
    using namespace std;
    using aliyun_log_sdk_v6::CodecTool;
    
    void Sign(const string& httpMethod, const string& uri,
              map<string, string>& httpHeaders,
              const map<string, string>& urlParams, const string& body,
              const string& accessKeyId, const string& accessKeySecret)
    {
        string message;
        string contentMd5, signature, contentType;
        httpHeaders["x-log-apiversion"] = "0.6.0";
        httpHeaders["x-log-signaturemethod"] = "hmac-sha1";
        // 1. Content-Md5
        if (!body.empty())
        {
            contentMd5 = CodecTool::CalcMD5(body);
            httpHeaders["Content-Md5"] = contentMd5;
        }
        // 2. 日付
        string dateTime = CodecTool::GetDateString();
        httpHeaders["Date"] = dateTime;
        // 3. Content-Length
        string contentLength = std::to_string(body.size());
        httpHeaders["Content-Length"] = contentLength;
        // 4. Content-Type
        if (httpHeaders.find("Content-Type") != httpHeaders.end())
        {
            contentType = httpHeaders["Content-Type"];
        }
        message.append(httpMethod).append("\n");
        message.append(contentMd5).append("\n");
        message.append(contentType).append("\n");
        message.append(dateTime).append("\n");
    
        // 5. ヘッダー
        map<string, string> filteredHeaders;
        for (auto it : httpHeaders)
        {
            string key = it.first, value = it.second;
            if (CodecTool::StartWith(key, "x-log-") ||
                     CodecTool::StartWith(key, "x-acs-"))
            {
                filteredHeaders[key] = value;
            }
        }
        for (auto it : filteredHeaders)
        {
            message.append(it.first).append(":").append(it.second);
            message.append("\n");
        }
    
        // 6. URI と URL パラメーター
        message.append(uri);
        if (urlParams.size() > 0) message.append("?");
        for (auto it = urlParams.begin(); it != urlParams.end(); ++it)
        {
            if (it != urlParams.begin())
            {
                message.append("&");
            }
            message.append(it->first).append("=").append(it->second);
        }
    
        // 7. 署名
        signature = CodecTool::Base64Encode(
            CodecTool::CalcHMACSHA1(message, accessKeySecret));
    
        // 8. 認可
        httpHeaders["Authorization"] =
            "LOG " + accessKeyId + ':' + signature;
    }
  • TypeScript のサンプルコード

    この例では crypto-js を使用します。依存関係をインストールします:

    npm install crypto-js --save

    署名の例:

    import CryptoJS from 'crypto-js'
    
    export function sign(
      method: string,
      uri: string,
      access_key_id: string,
      access_key_secret: string,
      params: Map<string, string>,
      headers: Map<string, string>,
      body: string | undefined
    ) {
      let content_length = 0
      let content_md5 = '',
        message = ''
       headers.set("x-log-apiversion", "0.6.0")
       headers.set("x-log-signaturemethod", "hmac-sha1")
      if (body !== undefined && body.length > 0) {
        content_length = body.length
        content_md5 = CryptoJS.MD5(body).toString(CryptoJS.enc.Hex).toUpperCase()
        headers.set('Content-MD5', content_md5)
      }
      const date = new Date().toUTCString()
      headers.set('Date', date)
      headers.set('Content-Length', content_length.toString())
      message +=
        method +
        '\n' +
        content_md5 +
        '\n' +
        (headers.get('Content-Type') ?? '') +
        '\n' +
        date +
        '\n'
      // ヘッダー
      const sort_by_key = (a: [string, string], b: [string, string]) =>
        a[0].localeCompare(b[0])
      const filter_by_prefix = (e: [string, string]) =>
        e[0].startsWith('x-log-') || e[0].startsWith('x-acs-')
      const header_str = [...headers.entries()]
        .filter(filter_by_prefix)
        .sort(sort_by_key)
        .map((e) => e[0] + ':' + e[1] + '\n')
        .join('')
      message += header_str
      // URI とクエリパラメーター
      message += uri
      if (params.size > 0) {
        message += '?'
      }
      message += [...params.entries()]
        .sort(sort_by_key)
        .map((e) => e[0] + '=' + e[1])
        .join('&')
      // 署名と認可
      const signature = CryptoJS.HmacSHA1(message, access_key_secret).toString(
        CryptoJS.enc.Base64
      )
      const auth = 'LOG ' + access_key_id + ':' + signature
      headers.set('Authorization', auth)
    }
    
    // 呼び出し例
    sign(
      'POST',
      '/logstores/test-logstore',
      'testAccessId',
      'testAccessKey',
      new Map<string, string>([
        ['test', 'test'],
        ['hello', 'world'],
      ]),
      new Map<string, string>([
        ['x-log-signaturemethod', 'hmac-sha1'],
        ['x-log-bodyrawsize', '0'],
        ['x-log-apiversion', '0.6.0'],
        ['Content-Type', 'application/json'],
      ]),
      'hello, world'
    )
                                
  • Rust のサンプルコード

    必要な依存関係:

    [dependencies]
    chrono = "0.4.19"
    md5 = "0.7.0"
    base64 = "0.13.0"
    hmac-sha1 = "0.1.3"

    署名の例:

    extern crate base64;
    extern crate hmac_sha1;
    extern crate md5;
    
    use chrono::Utc;
    use std::collections::*;
    
    pub fn sign(
        method: &str,
        uri: &str,
        access_key_id: &str,
        access_key_secret: &str,
        params: &HashMap<String, String>,
        headers: &mut HashMap<String, String>,
        body: Option<Vec<u8>>,
    ) -> String {
        let mut content_length = 0;
        let mut content_md5 = String::from("");
        headers.insert("x-log-apiversion".to_owned(), "0.6.0".to_owned());
        headers.insert("x-log-signaturemethod".to_owned(), "hmac-sha1".to_owned());
        if let Some(content) = body {
            if content.len() > 0 {
                content_length = content.len();
                content_md5 = format!("{:X}", md5::compute(content));
                headers.insert("Content-MD5".to_owned(), content_md5.clone());
            }
        }
        headers.insert("Content-Length".to_owned(), content_length.to_string());
        // 日付
        let date = Utc::now().format("%a, %d %b %Y %H:%M:%S GMT").to_string();
        headers.insert("Date".to_owned(), date.clone());
        let mut message = "".to_owned();
        let content_type = headers
            .get(&"Content-Type".to_owned())
            .cloned()
            .unwrap_or(String::from(""));
    
        message += format!("{}\n{}\n{}\n{}\n", method, content_md5, content_type, date).as_str();
        // ヘッダー
        let mut sorted_header: Vec<_> = headers.iter().collect();
        sorted_header.sort_by_key(|x| x.0);
        for (k, v) in sorted_header {
            if k.starts_with("x-log-") || k.starts_with("x-acs-") {
                message += format!("{}:{}\n", k, v).as_str();
            }
        }
    
        // URL とパラメーター
        message += uri;
        if params.len() > 0 {
            message += "?";
        }
        let mut sorted_params: Vec<_> = params.iter().collect();
        sorted_params.sort_by_key(|x| x.0);
        let mut sep = "";
        for (k, v) in sorted_params {
            message += format!("{}{}={}", sep, k, v).as_str();
            sep = "&";
        }
        let signature = base64::encode(hmac_sha1::hmac_sha1(
            access_key_secret.as_bytes(),
            message.as_bytes(),
        ));
        let auth = format!("LOG {}:{}", access_key_id, signature);
        headers.insert("Authorization".to_owned(), auth.to_owned());
        auth
    }