Partilhar via


Assinar uma solicitação HTTP usando o código de autenticação de mensagem baseado em hash (HMAC)

Este artigo descreve como assinar uma solicitação HTTP com uma assinatura de código de autenticação de mensagem baseada em hash (HMAC).

Note

Recomendamos usar os SDKs do Azure para assinar uma solicitação HTTP. A abordagem descrita neste artigo é uma opção de fallback se os SDKs do Azure não puderem ser usados por qualquer motivo.

Neste tutorial, você aprenderá a:

  • Crie uma mensagem de solicitação.
  • Crie um hash de conteúdo.
  • Calcule uma assinatura digital.
  • Crie uma cadeia de caracteres de cabeçalho de autorização.
  • Adicionar cabeçalhos.

Prerequisites

Assinar uma solicitação HTTP com C#

A autenticação de chave de acesso usa uma chave de segredo compartilhado para gerar uma assinatura HMAC para cada solicitação HTTP. Essa assinatura é gerada com o algoritmo SHA256 e é enviada no Authorization cabeçalho usando o HMAC-SHA256 esquema. Por exemplo:

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

Os hmac-sha256-signature são constituídos por:

  • Verbo HTTP (por exemplo, GET ou PUT)
  • Caminho de solicitação HTTP
  • x-ms-date
  • Host
  • x-ms-content-sha256

Configurar o cabeçalho de autorização

Conclua as etapas a seguir para construir o cabeçalho de autorização.

Criar um novo aplicativo C#

Em uma janela de console, como cmd, PowerShell ou Bash, use o dotnet new comando para criar um novo aplicativo de console com o nome SignHmacTutorial. Este comando cria um projeto C# "Hello World" simples com um único arquivo de origem: Program.cs.

dotnet new console -o SignHmacTutorial

Altere seu diretório para a pasta do aplicativo recém-criada. Para compilar seu aplicativo, use o dotnet build comando.

cd SignHmacTutorial
dotnet build

Instalar o pacote

Instale o pacote Newtonsoft.Json utilizado para serializar o corpo.

dotnet add package Newtonsoft.Json

Atualize a declaração de método para oferecer suporte a código assíncrono Main . Use o código a seguir para começar.

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.
        }
    }
}

Criar uma mensagem de solicitação

Neste exemplo, você assina uma solicitação para criar uma nova identidade usando a API de Autenticação dos Serviços de Comunicação (versão 2021-03-07).

Adicione o seguinte código ao método 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")
};

Substitua resourceEndpoint pelo valor real do ponto final do recurso.

Criar um hash de conteúdo

O hash de conteúdo faz parte da assinatura HMAC. Utilize o código seguinte para calcular o hash de conteúdo. Você pode adicionar esse método a Program.cs sob o Main método.

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

Calcular uma assinatura

Use o código a seguir para criar um método para calcular sua assinatura 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);
}

Substitua resourceAccessKey por uma chave de acesso do seu recurso real de Serviços de Comunicação.

Criar uma cadeia de caracteres de cabeçalho de autorização

Agora você constrói a cadeia de caracteres que adiciona ao cabeçalho de autorização.

  1. Prepare valores para os cabeçalhos a serem assinados.
    1. Especifique a marcação temporal atual usando o fuso horário do Tempo Universal Coordenado (UTC).
    2. Obtenha a autoridade de solicitação. Use o nome de host ou endereço IP do Sistema de Nomes de Domínio (DNS) e o número da porta.
    3. Calcule um hash de conteúdo.
  2. Prepare uma cadeia de caracteres para assinar.
  3. Calcule a assinatura.
  4. Concatena a cadeia de caracteres, que é usada no cabeçalho de autorização.

Adicione o seguinte código ao método 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}";

Adicionar cabeçalhos a requestMessage

Use o código a seguir para adicionar os cabeçalhos necessários ao seu requestMessage parâmetro.

// 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);

Testar o cliente

Chame o ponto de extremidade usando HttpCliente verifique a resposta.

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

Prerequisites

  • Crie uma conta do Azure com uma assinatura ativa. Se não tiver uma subscrição do Azure, consulte Criar uma conta gratuitamente.
  • Baixe e instale o Python.
  • Baixe e instale o Visual Studio Code ou outro ambiente de desenvolvimento integrado (IDE) que ofereça suporte a Python.
  • Criar um recurso do Azure Communication Services. Se não tiver um recurso, consulte Criar um recurso dos Serviços de Comunicação. Você precisa dos parâmetros resource_endpoint_name e resource_endpoint_secret para este exemplo.

Assinar uma solicitação HTTP com Python

A autenticação de chave de acesso usa uma chave de segredo compartilhado para gerar uma assinatura HMAC para cada solicitação HTTP. Essa assinatura é gerada com o algoritmo SHA256 e é enviada no Authorization cabeçalho usando o HMAC-SHA256 esquema. Por exemplo:

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

Os hmac-sha256-signature são constituídos por:

  • Verbo HTTP (por exemplo, GET ou PUT)
  • Caminho de solicitação HTTP
  • x-ms-date
  • Host
  • x-ms-content-sha256

Configurar o cabeçalho de autorização

Conclua as etapas a seguir para construir o cabeçalho de autorização.

Criar um novo script Python

Abra o Visual Studio Code ou outro IDE ou editor de sua escolha. Crie um novo arquivo chamado sign_hmac_tutorial.py. Salve este arquivo em uma pasta conhecida.

Adicionar importações necessárias

Atualize o sign_hmac_tutorial.py script com o seguinte código para começar.

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

Preparar dados para o pedido

Neste exemplo, você assina uma solicitação para criar uma nova identidade usando a API de Autenticação dos Serviços de Comunicação (versão 2021-03-07).

Adicione o seguinte código ao sign_hmac_tutorial.py script.

  • Substitua resource_endpoint_name pelo nome real do ponto de extremidade do recurso. Você pode encontrar esse valor na seção Visão geral do recurso Serviços de Comunicação. É o valor de Endpoint depois https://.
  • Substitua resource_endpoint_secret pelo valor secreto real do ponto de extremidade do recurso. Você pode encontrar esse valor na seção Chaves do recurso Serviços de Comunicação. É o valor de Key, que é primário ou secundário.
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")

Criar um hash de conteúdo

O hash de conteúdo faz parte da assinatura HMAC. Utilize o código seguinte para calcular o hash de conteúdo. Você pode adicionar esse método ao sign_hmac_tutorial.py script.

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

Calcular uma assinatura

Use o código a seguir para criar um método para calcular sua assinatura 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

Obter um timestamp UTC atual de acordo com o padrão RFC1123

Use o código a seguir para obter o formato de data desejado que é independente das configurações de localidade.

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)

Criar uma cadeia de caracteres de cabeçalho de autorização

Agora você constrói a cadeia de caracteres que adiciona ao cabeçalho de autorização.

  1. Prepare valores para os cabeçalhos a serem assinados.
    1. Especifique a marcação temporal atual usando o fuso horário do Tempo Universal Coordenado (UTC).
    2. Obtenha a autoridade de solicitação. Use o nome de host ou endereço IP do Sistema de Nomes de Domínio (DNS) e o número da porta.
    3. Calcule um hash de conteúdo.
  2. Prepare uma cadeia de caracteres para assinar.
  3. Calcule a assinatura.
  4. Concatena a cadeia de caracteres, que é usada no cabeçalho de autorização.

Adicione o seguinte código ao sign_hmac_tutorial.py script.

# 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}"

Adicionar cabeçalhos

Use o código a seguir para adicionar os cabeçalhos necessários.

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"

Testar o cliente

Chame o endpoint e verifique a resposta.

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

Limpar recursos

Para limpar e remover uma assinatura dos Serviços de Comunicação, exclua o recurso ou grupo de recursos. A exclusão do grupo de recursos também exclui quaisquer outros recursos associados a ele. Você pode saber mais sobre como limpar os recursos dos Serviços de Comunicação do Azure e limpar os recursos do Azure Functions.