次の方法で共有


ハッシュベースのメッセージ認証コード (HMAC) を使用した HTTP リクエストの署名

この記事では、ハッシュベースのメッセージ認証コード (HMAC) 署名を使用して HTTP 要求に署名する方法について説明します。

Azure SDK を使用して HTTP 要求に署名することをお勧めします。 この記事で説明するアプローチは、何らかの理由で Azure SDK を使用できない場合のフォールバック オプションです。

このチュートリアルでは、以下の内容を学習します。

  • リクエストメッセージを作成します。
  • コンテンツ ハッシュを作成します。
  • 署名を計算します。
  • 認証ヘッダー文字列を作成します。
  • ヘッダーを追加します。

前提条件

  • アクティブなサブスクリプションがある Azure アカウントを作成します。 Azure サブスクリプションをお持ちでない場合は、「 無料でアカウントを作成する」を参照してください。
  • Visual Studio のインストール。
  • Azure Communication Services リソースを作成します。 リソースがない場合は、「 Communication Services リソースの作成」を参照してください。 このチュートリアルでは、 resourceEndpoint パラメーターと resourceAccessKey パラメーターを記録する必要があります。

C# で HTTP 要求に署名する

アクセス キー認証では、共有秘密鍵を使用して、HTTP 要求ごとに HMAC 署名が生成されます。 この署名は SHA256 アルゴリズムを使用して生成され、Authorization スキームを使用して HMAC-SHA256 ヘッダーで送信されます。 次に例を示します。

Authorization: "HMAC-SHA256 SignedHeaders=x-ms-date;host;x-ms-content-sha256&Signature=<hmac-sha256-signature>"

hmac-sha256-signature は次の要素で構成されます。

  • HTTP 動詞 (たとえば、GET または PUT)
  • HTTP 要求パス
  • X-MS-日付
  • ホスト
  • X-MS-コンテンツSHA256

認証ヘッダーを設定する

以下のステップを実行して、認証ヘッダーを作成します。

新しい C# アプリケーションを作成する

cmd、PowerShell、Bash などのコンソール ウィンドウで dotnet new コマンドを使用して、新しいコンソール アプリを SignHmacTutorial という名前で作成します。 このコマンドにより、1 つのソース ファイル (Program.cs) を使用する単純な "Hello World" C# プロジェクトが作成されます。

dotnet new console -o SignHmacTutorial

新しく作成されたアプリ フォルダーにディレクトリを変更します。 アプリケーションをコンパイルするには、 dotnet build コマンドを使用します。

cd SignHmacTutorial
dotnet build

パッケージをインストールする

本文のシリアル化に使用する Newtonsoft.Json パッケージをインストールします。

dotnet add package Newtonsoft.Json

非同期コードをサポートするように Main メソッドの宣言を更新します。 次のコードを使用して開始します。

using System;
using System.Globalization;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace SignHmacTutorial
{
    class Program
    {
        static async Task Main(string[] args)
        {
            Console.WriteLine("Azure Communication Services - Sign an HTTP request Tutorial");
            // Tutorial code goes here.
        }
    }
}

要求メッセージを作成する

この例では、Communication Services Authentication API (バージョン 2021-03-07) を使用して、新しい ID を作成する要求に署名します。

Main メソッドに次のコードを追加します。

string resourceEndpoint = "resourceEndpoint";
// Create a uri you are going to call.
var requestUri = new Uri($"{resourceEndpoint}/identities?api-version=2021-03-07");
// Endpoint identities?api-version=2021-03-07 accepts list of scopes as a body
var body = new
    {
        createTokenWithScopes = new[] { "chat" }
    };

var serializedBody = JsonConvert.SerializeObject(body);

var requestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri)
{
    Content = new StringContent(serializedBody, Encoding.UTF8, "application/json")
};

resourceEndpoint を実際のリソース エンドポイント値に置き換えます。

コンテンツ ハッシュを作成する

コンテンツ ハッシュは、HMAC 署名の一部です。 コンテンツ ハッシュを計算するには、次のコードを使用します。 このメソッドは、Program.csMain メソッドの下に追加できます。

static string ComputeContentHash(string content)
{
    using var sha256 = SHA256.Create();
    byte[] hashedBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(content));
    return Convert.ToBase64String(hashedBytes);
}

署名を計算する

次のコードを使用して、HMAC 署名を計算するためのメソッドを作成します。

static string ComputeSignature(string stringToSign)
{
    string secret = "resourceAccessKey";
    using var hmacsha256 = new HMACSHA256(Convert.FromBase64String(secret));
    var bytes = Encoding.UTF8.GetBytes(stringToSign);
    var hashedBytes = hmacsha256.ComputeHash(bytes);
    return Convert.ToBase64String(hashedBytes);
}

resourceAccessKey は実際の Communication Services リソースのアクセス キーに置き換えてください。

Authorization ヘッダー文字列を作成する

次に、認証ヘッダーに追加する文字列を作成します。

  1. 署名するヘッダーの値を準備します。
    1. 現在のタイムスタンプは、協定世界時 (UTC) タイムゾーンを使用して指定します。
    2. 要求権限を取得します。 ドメイン ネーム システム (DNS) のホスト名または IP アドレスとポート番号を使用します。
    3. コンテンツ ハッシュを計算します。
  2. 署名する文字列を準備します。
  3. 署名を計算します。
  4. 認証ヘッダーで使用される文字列を連結します。

Main メソッドに次のコードを追加します。

// Specify the 'x-ms-date' header as the current UTC timestamp according to the RFC1123 standard.
var date = DateTimeOffset.UtcNow.ToString("r", CultureInfo.InvariantCulture);
// Get the host name corresponding with the 'host' header.
var host = requestUri.Authority;
// Compute a content hash for the 'x-ms-content-sha256' header.
var contentHash = ComputeContentHash(serializedBody);

// Prepare a string to sign.
var stringToSign = $"POST\n{requestUri.PathAndQuery}\n{date};{host};{contentHash}";
// Compute the signature.
var signature = ComputeSignature(stringToSign);
// Concatenate the string, which will be used in the authorization header.
var authorizationHeader = $"HMAC-SHA256 SignedHeaders=x-ms-date;host;x-ms-content-sha256&Signature={signature}";

requestMessage にヘッダーを追加する

次のコードを使用して、必要なヘッダーを requestMessage パラメーターに追加します。

// Add a date header.
requestMessage.Headers.Add("x-ms-date", date);

// Add a host header.
// In C#, the 'host' header is added automatically by the 'HttpClient'. However, this step may be required on other platforms such as Node.js.

// Add a content hash header.
requestMessage.Headers.Add("x-ms-content-sha256", contentHash);

// Add an authorization header.
requestMessage.Headers.Add("Authorization", authorizationHeader);

クライアントのテスト

HttpClient を使用してエンドポイントを呼び出し、応答を確認します。

HttpClient httpClient = new HttpClient
{
    BaseAddress = requestUri
};
var response = await httpClient.SendAsync(requestMessage);
var responseString = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseString);

前提条件

  • アクティブなサブスクリプションがある Azure アカウントを作成します。 Azure サブスクリプションをお持ちでない場合は、「 無料でアカウントを作成する」を参照してください。
  • Python をダウンロードしてインストールします。
  • Visual Studio Code または Python をサポートする別の統合開発環境 (IDE) をダウンロードしてインストールします。
  • Azure Communication Services リソースを作成します。 リソースがない場合は、「 Communication Services リソースの作成」を参照してください。 この例では、 resource_endpoint_name パラメーターと resource_endpoint_secret パラメーターが必要です。

Python で HTTP 要求に署名する

アクセス キー認証では、共有秘密鍵を使用して、HTTP 要求ごとに HMAC 署名が生成されます。 この署名は SHA256 アルゴリズムを使用して生成され、Authorization スキームを使用して HMAC-SHA256 ヘッダーで送信されます。 次に例を示します。

Authorization: "HMAC-SHA256 SignedHeaders=x-ms-date;host;x-ms-content-sha256&Signature=<hmac-sha256-signature>"

hmac-sha256-signature は次の要素で構成されます。

  • HTTP 動詞 (たとえば、GET または PUT)
  • HTTP 要求パス
  • X-MS-日付
  • ホスト
  • X-MS-コンテンツSHA256

認証ヘッダーを設定する

以下のステップを実行して、認証ヘッダーを作成します。

新しい Python スクリプトを作成する

Visual Studio Code または選択した別の IDE またはエディターを開きます。 sign_hmac_tutorial.py という名前で新しいファイルを作成します。 このファイルを既知のフォルダーに保存します。

必要なインポートを追加する

次のコードを使用して、sign_hmac_tutorial.py スクリプトを更新して開始します。

import base64
import hashlib
import hmac
import json
from datetime import datetime, timezone
from urllib import request

要求に向けてデータを準備する

この例では、Communication Services Authentication API (バージョン 2021-03-07) を使用して新しい ID を作成する要求に署名します。

次のコードを sign_hmac_tutorial.py スクリプトに追加します。

  • resource_endpoint_name を実際のリソース エンドポイントの名前の値に置き換えます。 この値は、Communication Services リソースの [概要 ] セクションで確認できます。 これは、https://後のEndpointの値です。
  • resource_endpoint_secret を実際のリソース エンドポイントのシークレット値に置き換えます。 この値は、Communication Services リソースの [キー ] セクションで確認できます。 これは Key の値で、プライマリまたはセカンダリのいずれかです。
host = "resource_endpoint_name"
resource_endpoint = f"https://{host}"
path_and_query = "/identities?api-version=2021-03-07"
secret = "resource_endpoint_secret"

# Create a uri you are going to call.
request_uri = f"{resource_endpoint}{path_and_query}"

# Endpoint identities?api-version=2021-03-07 accepts the list of scopes as a body.
body = { "createTokenWithScopes": ["chat"] }

serialized_body = json.dumps(body)
content = serialized_body.encode("utf-8")

コンテンツ ハッシュを作成する

コンテンツ ハッシュは、HMAC 署名の一部です。 コンテンツ ハッシュを計算するには、次のコードを使用します。 このメソッドを sign_hmac_tutorial.py スクリプトに追加できます。

def compute_content_hash(content):
    sha_256 = hashlib.sha256()
    sha_256.update(content)
    hashed_bytes = sha_256.digest()
    base64_encoded_bytes = base64.b64encode(hashed_bytes)
    content_hash = base64_encoded_bytes.decode('utf-8')
    return content_hash

署名を計算する

次のコードを使用して、HMAC 署名を計算するためのメソッドを作成します。

def compute_signature(string_to_sign, secret):
    decoded_secret = base64.b64decode(secret)
    encoded_string_to_sign = string_to_sign.encode('utf-8')
    hashed_bytes = hmac.digest(decoded_secret, encoded_string_to_sign, digest=hashlib.sha256)
    encoded_signature = base64.b64encode(hashed_bytes)
    signature = encoded_signature.decode('utf-8')
    return signature

RFC1123標準に従って現在のUTCタイムスタンプを取得する

次のコードを使用して、ロケール設定に依存しない必要な日付形式を取得します。

def format_date(dt):
    days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
    months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
    utc = dt.utctimetuple()

    return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format(
    days[utc.tm_wday],
    utc.tm_mday,
    months[utc.tm_mon-1],
    utc.tm_year,
    utc.tm_hour, 
    utc.tm_min, 
    utc.tm_sec)

Authorization ヘッダー文字列を作成する

次に、認証ヘッダーに追加する文字列を作成します。

  1. 署名するヘッダーの値を準備します。
    1. 現在のタイムスタンプは、協定世界時 (UTC) タイムゾーンを使用して指定します。
    2. 要求権限を取得します。 ドメイン ネーム システム (DNS) のホスト名または IP アドレスとポート番号を使用します。
    3. コンテンツ ハッシュを計算します。
  2. 署名する文字列を準備します。
  3. 署名を計算します。
  4. 認証ヘッダーで使用される文字列を連結します。

次のコードを sign_hmac_tutorial.py スクリプトに追加します。

# Specify the 'x-ms-date' header as the current UTC timestamp according to the RFC1123 standard.
utc_now = datetime.now(timezone.utc)
date = format_date(utc_now)
# Compute a content hash for the 'x-ms-content-sha256' header.
content_hash = compute_content_hash(content)

# Prepare a string to sign.
string_to_sign = f"POST\n{path_and_query}\n{date};{host};{content_hash}"
# Compute the signature.
signature = compute_signature(string_to_sign, secret)
# Concatenate the string, which will be used in the authorization header.
authorization_header = f"HMAC-SHA256 SignedHeaders=x-ms-date;host;x-ms-content-sha256&Signature={signature}"

ヘッダーの追加

次のコードを使用して、必要なヘッダーを追加します。

request_headers = {}

# Add a date header.
request_headers["x-ms-date"] = date

# Add a content hash header.
request_headers["x-ms-content-sha256"] = content_hash

# Add an authorization header.
request_headers["Authorization"] = authorization_header

# Add a content type header.
request_headers["Content-Type"] = "application/json"

クライアントのテスト

エンドポイントを呼び出して、応答を確認します。

req = request.Request(request_uri, content, request_headers, method='POST')
with request.urlopen(req) as response:
  response_string = json.load(response)
print(response_string)

リソースをクリーンアップする

Communication Services サブスクリプションをクリーンアップして削除するには、リソースまたはリソース グループを削除します。 リソース グループを削除すると、それに関連付けられている他のリソースも削除されます。 Azure Communication Services リソースをクリーンアップする方法と Azure Functions リソースをクリーンアップする方法の詳細については、こちらを参照してください。