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

Simple Log Service:リクエストの署名

最終更新日:Sep 04, 2024

Simple Log Service API操作の各HTTPリクエストは、ログデータセキュリティを確保するためにセキュリティ検証に合格する必要があります。 Simple Log Serviceは、Alibaba Cloud AccessKeyペアと非対称暗号化アルゴリズムを使用してAPIリクエストを検証します。

使用上の注意

Simple Log Service SDKは、Simple Log ServiceのすべてのAPI操作をカプセル化します。 Simple Log Service SDKを使用して、Simple Log Service API操作を効率的に呼び出すことができます。 Simple Log Service SDKは自動的にリクエストに署名し、複数のプログラミング言語をサポートします。 SDKを使用してSimple Log Serviceにアクセスすることを推奨します。 詳細については、「Simple Log Service SDKの概要」をご参照ください。

Simple Log Serviceは、セキュリティ検証プロセスで次の操作を実行します。

  • APIリクエストを送信するユーザーを特定します。

    ユーザーがAPIリクエストを送信する前に、APIリクエストのデジタル署名を生成するためにAccessKeyペアを指定する必要があります。 Simple Log Serviceは、AccessKeyペアを使用してユーザーを識別し、アクセス制御を実装します。

  • 送信中にAPIリクエストが改ざんされていないか確認してください。

    Simple Log ServiceがAPIリクエストを受信すると、Simple Log ServiceはAPIリクエストのデジタル署名を計算し、その署名をクライアント側で生成された署名と比較します。 送信中に要求が改ざんされた場合、2つの署名は一致せず、検証は失敗します。

APIリクエストのデジタル署名を生成するには、AccessKeyペアを使用する必要があります。 詳細は、「AccessKeyペア」をご参照ください。 既存のAccessKeyペアを使用するか、AccessKeyペアを作成できます。 AccessKeyペアが有効であることを確認します。

以下のセクションでは、リクエスト構造と署名の計算プロセスについて説明します。 次のセクションでは、署名を生成する方法を示すさまざまなプログラミング言語のサンプルコードについても説明します。

リクエストの構造

次の表に、有効なAPIリクエストに必要なHTTPヘッダーフィールドを示します。 フィールドのキーと値のペアを指定する必要があります。 値は大文字と小文字を区別します。

項目

説明

x-log-signaturemethod

リクエストの暗号化方法。

hmac-sha1

x-log-apiversion

リクエストのAPIバージョン。

0.6.0

日付

HTTPリクエストの標準タイムスタンプヘッダー。 ヘッダーは、RFC 822またはRFC 1123で定義されている時間形式に従い、GMTの時間値を表します。 フォーマット: % a, % d % b % Y % H:% M:% S GMT

Mon, 3 Jan 2010 08:33:47 GMT

Content-MD5

HTTPリクエストボディのMD5ハッシュ値。 MD5ハッシュ値を16進文字列に変換する必要があります。

72A15D7DE7EE9E7BB86461FFEA9499

承認

署名。 形式: LOG accessKeyId:Signature accessKeyIdはAccessKey IDを指定します。 Signatureは署名文字列を指定します。 署名文字列の詳細については、「署名計算プロセス」をご参照ください。

ログtestAccessKeyId:RLETq4u7sWb3cssZIhsun ****

Content-Type

HTTP リクエストボディの型 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フィールドは、署名構造に必要です。 許可フィールドは、accessKeyIdフィールドとSignatureフィールドを連結するLOG AccessKeyId: Signature形式です。 accessKeyIdはAccessKey IDを指定し、Signatureは署名文字列を指定します。 このセクションでは、signatureフィールドの署名文字列を作成する方法について説明します。

署名メッセージ

署名文字列は、署名メッセージを暗号化および符号化することによって生成される。 次の図は、署名メッセージの作成方法を示しています。

image

パラメーター

説明

method

HTTP リクエストの方式。 値には大文字のみを使用できます。 有効な値: GET、POST、PUT、およびDELETE。

GET

Content-MD5

HTTPリクエストボディのMD5ハッシュ値。 値を大文字を含む16進文字列に変換する必要があります。 HTTPリクエスト本文が存在しない場合、値は空の文字列です。

49DFDD54B01CBCD2D2AB5E9E5EE6B9B9

Content-Type

HTTP リクエストボディの型 HTTPリクエスト本文が存在しない場合、値は空の文字列になります。

application/json

日付

現在の時刻の書式付き文字列。 この文字列は、RFC 822またはRFC 1123で定義されている時間形式に従い、GMTの時間値を表します。 フォーマット: % a, % d % b % Y % H:% M:% S GMT

Mon, 3 Jan 2010 08:33:47 GMT

ヘッダー

先頭にx-log- またはx-acs- が付いているヘッダーフィールド。 フィールドはキーと値のペアで、キーと値のペアはキーごとに昇順にソートされます。 キーと値のペアのキーと値は、コロン (:) で接続されています。 キーと値のペアは改行で区切られます。

  • x-log-apiversion:0.6.0

  • x-log-bodyrawsize:0

  • x-log-signaturemethod:hmac-sha1

ウリ

リクエストパス。 ドメイン名とクエリ関連のパラメーターは除外されます。

/logstores/test-logstore

クエリ関連のパラメーター

クエリ関連のパラメーター。 パラメーターはキーと値のペアで、キーと値のペアはキーごとに昇順にソートされます。 キーと値のペアのキーと値は、等号 (=) で接続されています。 キーと値のペアはアンパサンド (&) で区切ります。

オフセット=1&サイズ=10

次のサンプルコードは、署名メッセージの例を示しています。 最后の行を除いて、各行は改行で终わります。

POST
1572A15D7DE7EE9E7BB86461FFEA9499
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. HMAC-SHA1アルゴリズムとAccessKeyシークレットを使用してメッセージを暗号化し、暗号化結果のハッシュ値を取得します。

  3. Base64でハッシュ値をエンコードして署名文字列を生成します。

このセクションでは、APIリクエストに署名する方法の例を示します。 署名プロセスの例として、次のAccessKey IDとAccessKey secretを使用します。

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リクエストにはHTTPリクエストボディは含まれません。 したがって、Content-MD5およびContent-Typeフィールドの値は空の文字列になります。 次の署名文字列は、指定されたAccessKeyシークレットを使用して生成されます。

    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という名前の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-signaturemethod:hmac-sha1
    Content-MD5: 1DD45FA4A70A9300CC9FE7305AF2C494
    Content-Length: 52
    <The log is serialized into byte streams in the Protobuf format.>

    ログはプロトコルバッファ (Protobuf) 形式のバイトストリームにシリアル化され、HTTPリクエストボディとして使用されます。 Protobuf形式の詳細については、「データエンコーディング」をご参照ください。 リクエストでは、Content-Typeフィールドの値はapplication/x-protobufです。 Content-MD5フィールドの値は、HTTPリクエストボディの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/ali-test-logstore

    次の署名文字列は、指定されたAccessKeyシークレットを使用して生成されます。

    XWLGYHGg2F2hcfxWxMLiNk****

    次のサンプルコードは、署名付きHTTPリクエストを示しています。

    POST /logstores/ali-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****
    <The log is serialized into byte streams in the Protobuf format.>

サンプルコード

  • サンプルコードin Java

    次のサンプルコードでは、commons-codecサードパーティ製ライブラリを使用しています。 次のMaven依存関係をpom.xmlに追加します。

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

    次のサンプルコードは、APIリクエストに署名する方法の例を示しています。

    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";
            // header
            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 & params
            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("&"));
            // signature & authorization
            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のサンプルコード

    次のサンプルコードは、APIリクエストに署名する方法の例を示しています。

    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"
    
        # header
        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 and params
        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 = '&'
        # signature and authorization
        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のサンプルコード

    次のサンプルコードは、APIリクエストに署名する方法の例を示しています。

    <?php
    // returns new headers array
    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;
      }
      // date
      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";
      // header
      $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 and params
      $message .= $uri;
      if (sizeof($params) > 0) {
        $message .= '?';
      }
      ksort($params);
      $sep = '';
      foreach ($params as $key => $val) {
        $message .= $sep . $key . '=' . $val;
        $sep = '&';
      }
      // signature & authorization
      $signature = base64_encode(hash_hmac('sha1', $message, $accessKeySecret, TRUE));
      $auth = 'LOG ' . $accessKeyId . ':' . $signature;
      $headers['Authorization'] = $auth;
      return $headers;
    };
    
    // example call
    $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のサンプルコード

    次のサンプルコードは、APIリクエストに署名する方法の例を示しています。

    package sls
    
    import (
        "crypto/hmac"
        "crypto/md5"
        "crypto/sha1"
        "encoding/base64"
        "fmt"
        "sort"
        "strconv"
        "strings"
        "time"
    )
    
    
    /*
    * @param uri The uri of http request, exclude host and query param, eg: /logstores/test-logstore
    * @param headers This function modifies headers, headers must not be a nil map
    * @param method Http method in uppercase , eg: 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"
    
        // header
        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 = "&"
        })
    
        // Signature = base64(hmac-sha1(UTF8-Encoding-Of(SignString),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# のサンプルコード

    次のサンプルコードは、APIリクエストに署名する方法の例を示しています。

    System.Security.Cryptographyを使用した

    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;
      // header
      foreach (var entry in sortedHeader)
      {
        if (entry.Key.StartsWith("x-log-") || entry.Key.StartsWith("x-acs-"))
        {
          message += entry.Key + ":" + entry.Value + "\n";
        }
      }
      // url & params
      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 ++ のサンプルコード

    次のサンプルコードは、APIリクエストに署名する方法の例を示しています。 ビジネス要件に基づいて、コードにヘルパー関数を実装する必要があります。 サンプルコードのadapter.hヘッダーファイルは、Simple Log Service SDK for C ++ に属しています。 Simple Log Service SDK for C ++ に基づいてリクエストに署名することを推奨します。 詳細については、「Simple Log Service SDK For C ++ の使用を開始する」をご参照ください。

    • CodecTool::CalcMD5 (文字列): 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 例: 1月3日月曜日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. Date
        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. header
        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 and url params
        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
        signature = CodecTool::Base64Enconde(
            CodecTool::CalcHMACSHA1(message, accessKeySecret));
    
        // 8. authorization
        httpHeaders["authorization"] =
            "LOG " + accessKeyId + ':' + signature;
    }
  • TypeScriptのサンプルコード

    次のサンプルコードでは、crypto-jsのサードパーティライブラリを使用しています。 以下のコマンドを実行して、依存関係をインストールします。

    npm install crypto-js -- save

    次のサンプルコードは、APIリクエストに署名する方法の例を示しています。

    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'
      // headers
      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 & query params
      message += uri
      if (params.size > 0) {
        message += '?'
      }
      message += [...params.entries()]
        .sort(sort_by_key)
        .map((e) => e[0] + '=' + e[1])
        .join('&')
      // signature & authorization
      const signature = CryptoJS.HmacSHA1(message, access_key_secret).toString(
        CryptoJS.enc.Base64
      )
      const auth = 'LOG ' + access_key_id + ':' + signature
      headers.set('Authorization', auth)
    }
    
    // example call
    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"

    次のサンプルコードは、APIリクエストに署名する方法の例を示しています。

    extern crate base64;
    extern crate hmacsha1;
    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());
        // date
        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();
        // header
        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 & params
        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(hmacsha1::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
    }