HTTP 요청 서명
이 자습서에서는 HMAC 서명을 사용하여 HTTP 요청에 서명하는 방법을 알아봅니다.
참고 항목
Azure SDK를 사용하는 것이 좋습니다. 여기에 설명된 접근 방식은 어떤 이유로든 Azure SDK를 사용할 수 없는 경우에 대한 대체 옵션입니다.
필수 조건
시작하기 전에 다음을 확인해야 합니다.
- 활성 구독이 있는 Azure 계정을 만듭니다. 자세한 내용은 체험 계정 만들기를 참조하세요.
- Visual Studio를 설치합니다.
- Azure Communication Services 리소스를 만듭니다. 자세한 내용은 Azure Communication Services 리소스 만들기를 참조하세요. 이 자습서에서는 resourceEndpoint 및 resourceAccessKey를 기록해야 합니다.
C#에 HTTP 요청 서명
액세스 키 인증은 공유 비밀 키를 사용하여 각 HTTP 요청에 대해 HMAC 서명을 생성합니다. 이 서명은 SHA256 알고리즘을 사용하여 생성되며 HMAC-SHA256
체계를 사용하여 Authorization
헤더에 전송됩니다. 예시:
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-date
- Host
- x-ms-content-sha256
설정
다음 단계에서는 인증 헤더를 생성하는 방법을 설명합니다.
새 C# 애플리케이션 만들기
콘솔 창(예: cmd, PowerShell 또는 Bash)에서 dotnet new
명령을 사용하여 SignHmacTutorial
이라는 새 콘솔 앱을 만듭니다. 이 명령은 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 서명의 일부입니다. 다음 코드를 추가하여 콘텐츠 해시를 컴퓨팅합니다. 이 메서드를 Main
메서드 아래 Progam.cs
에 추가할 수 있습니다.
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 리소스의 액세스 키로 바꿉니다.
권한 부여 헤더 문자열 만들기
이제 권한 부여 헤더에 추가할 문자열을 구성합니다.
- 서명할 헤더의 값을 준비합니다.
- 협정 세계시(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 계정을 만듭니다. 자세한 내용은 체험 계정 만들기를 참조하세요.
- Python 다운로드하고 설치합니다.
- Python을 지원하는 Visual Studio Code 또는 기타 IDE를 다운로드하고 설치합니다.
- Azure Communication Services 리소스를 만듭니다. 자세한 내용은 Azure Communication Services 리소스 만들기를 참조하세요. 이 자습서에는 resource_endpoint_name 및 resource_endpoint_secret이 필요합니다.
Python을 사용하여 HTTP 요청 서명
액세스 키 인증은 공유 비밀 키를 사용하여 각 HTTP 요청에 대해 HMAC 서명을 생성합니다. 이 서명은 SHA256 알고리즘을 사용하여 생성되며 HMAC-SHA256
체계를 사용하여 Authorization
헤더에 전송됩니다. 예시:
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-date
- Host
- x-ms-content-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 인증 API (버전 2021-03-07
)를 사용하여 새 ID를 만들도록 요청에 서명합니다.
sign_hmac_tutorial.py
스크립트에 다음 코드를 추가합니다.
resource_endpoint_name
을 실제 리소스 엔드포인트 이름 값으로 바꿉니다. 이 값은 Azure Communication Services 리소스의 개요 섹션에서 찾을 수 있습니다. 이 값은 “https://” 뒤에 있는 “엔드포인트” 값입니다.resource_endpoint_secret
을 실제 리소스 엔드포인트 비밀 값으로 바꿉니다. 이 값은 Azure Communication Services 리소스의 키 섹션에서 찾을 수 있습니다. 이 값은 “키” 값(기본 또는 보조)입니다.
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 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)
권한 부여 헤더 문자열 만들기
이제 권한 부여 헤더에 추가할 문자열을 구성합니다.
- 서명할 헤더의 값을 준비합니다.
- 협정 세계시(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 content hash header.
request_headers["x-ms-content-sha256"] = content_hash
# Add authorization header.
request_headers["Authorization"] = authorization_header
# Add 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 리소스 정리에 대해 자세히 알아볼 수 있습니다.
다음 단계
다음을 수행할 수도 있습니다.