この記事では、ハッシュベースのメッセージ認証コード (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.cs
の Main
メソッドの下に追加できます。
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 ヘッダー文字列を作成する
次に、認証ヘッダーに追加する文字列を作成します。
- 署名するヘッダーの値を準備します。
- 現在のタイムスタンプは、協定世界時 (UTC) タイムゾーンを使用して指定します。
- 要求権限を取得します。 ドメイン ネーム システム (DNS) のホスト名または IP アドレスとポート番号を使用します。
- コンテンツ ハッシュを計算します。
- 署名する文字列を準備します。
- 署名を計算します。
- 認証ヘッダーで使用される文字列を連結します。
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 ヘッダー文字列を作成する
次に、認証ヘッダーに追加する文字列を作成します。
- 署名するヘッダーの値を準備します。
- 現在のタイムスタンプは、協定世界時 (UTC) タイムゾーンを使用して指定します。
- 要求権限を取得します。 ドメイン ネーム システム (DNS) のホスト名または IP アドレスとポート番号を使用します。
- コンテンツ ハッシュを計算します。
- 署名する文字列を準備します。
- 署名を計算します。
- 認証ヘッダーで使用される文字列を連結します。
次のコードを 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 リソースをクリーンアップする方法の詳細については、こちらを参照してください。