Partager via


Signer une requête HTTP à l’aide du code d’authentification de message basé sur le hachage (HMAC)

Cet article explique comment signer une requête HTTP avec une signature HMAC (Code d’authentification de message basé sur un hachage).

Note

Nous vous recommandons d’utiliser les Kits de développement logiciel (SDK) Azure pour signer une requête HTTP. L’approche décrite dans cet article est une option de secours si les Kits de développement logiciel (SDK) Azure ne peuvent pas être utilisés pour une raison quelconque.

Dans ce tutoriel, vous allez apprendre à :

  • Créez un message de demande.
  • Créer un hachage de contenu.
  • Calculez une signature.
  • Créez une chaîne d’en-tête d’autorisation.
  • Ajouter les en-têtes.

Prerequisites

Signer une requête HTTP avec C#

L’authentification par clé d’accès utilise une clé secrète partagée afin de générer une signature HMAC pour chaque requête HTTP. Cette signature est générée avec l’algorithme SHA256 et est envoyée dans l’en-tête Authorization à l’aide du schéma HMAC-SHA256. Par exemple:

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

La signature hmac-sha256-signature est constituée des éléments suivants :

  • Verbe HTTP (par exemple GET ou PUT)
  • Un chemin de requête HTTP
  • x-ms-date
  • Host
  • x-ms-content-sha256

Configurer l’en-tête d’autorisation

Effectuez les étapes suivantes pour construire l’en-tête d’autorisation.

Créer une application C#

Dans une fenêtre de console (par exemple cmd, PowerShell ou Bash), utilisez la commande dotnet new pour créer une application console avec le nom SignHmacTutorial. Cette commande crée un projet C# « Hello World » simple avec un seul fichier source : Program.cs.

dotnet new console -o SignHmacTutorial

Déplacez vos répertoires vers le dossier d’application nouvellement créé. Pour compiler votre application, utilisez la dotnet build commande.

cd SignHmacTutorial
dotnet build

Installer le package

Installez le package Newtonsoft.Json, utilisé pour la sérialisation du corps.

dotnet add package Newtonsoft.Json

Mettez à jour la déclaration de la méthode Main pour prendre en charge le code asynchrone. Utilisez le code suivant pour commencer.

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

Créer un message de requête

Pour cet exemple, vous signez une demande pour créer une identité à l’aide de l’API d’authentification Communication Services (version 2021-03-07).

Ajoutez le code suivant à la méthode 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")
};

Remplacez resourceEndpoint par votre valeur de point de terminaison de ressource réelle.

Créer un hachage de contenu

Le hachage de contenu fait partie de votre signature HMAC. Utilisez le code suivant pour calculer le hachage de contenu. Vous pouvez ajouter cette méthode à Program.cs sous la méthode Main.

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

Calculer une signature

Utilisez le code suivant pour créer une méthode destinée à calculer votre signature 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);
}

Remplacez resourceAccessKey par la clé d’accès de votre ressource Communication Services réelle.

Créer une chaîne d’en-tête d’autorisation

Maintenant, vous construisez la chaîne que vous ajoutez à votre en-tête d’autorisation.

  1. Préparez les valeurs des en-têtes à signer.
    1. Spécifiez l’horodatage actuel à l’aide du fuseau horaire UTC (Temps universel coordonné).
    2. Obtenez l'autorisation requise. Utilisez le nom d’hôte ou l’adresse IP DNS (Domain Name System) et le numéro de port.
    3. Calculer un hachage de contenu.
  2. Préparer une chaîne à signer.
  3. Calculer la signature.
  4. Concaténer la chaîne qui est utilisée dans l’en-tête d’autorisation.

Ajoutez le code suivant à la méthode 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}";

Ajouter des en-têtes à requestMessage

Utilisez le code suivant pour ajouter les en-têtes requis à votre requestMessage paramètre.

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

Tester le client

Appelez le point de terminaison à l’aide de HttpClient, puis vérifiez la réponse.

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

Prerequisites

  • Créer un compte Azure avec un abonnement actif. Si vous n’avez pas d’abonnement Azure, consultez Créer un compte gratuitement.
  • Téléchargez et installez Python.
  • Téléchargez et installez Visual Studio Code ou un autre environnement de développement intégré (IDE) qui prend en charge Python.
  • Créer une ressource Azure Communication Services. Si vous ne disposez pas d'une ressource, consultez Créer une ressource Azure Communication Services. Vous avez besoin de vos paramètres resource_endpoint_name et resource_endpoint_secret pour cet exemple.

Signer une requête HTTP avec Python

L’authentification par clé d’accès utilise une clé secrète partagée afin de générer une signature HMAC pour chaque requête HTTP. Cette signature est générée avec l’algorithme SHA256 et est envoyée dans l’en-tête Authorization à l’aide du schéma HMAC-SHA256. Par exemple:

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

La signature hmac-sha256-signature est constituée des éléments suivants :

  • Verbe HTTP (par exemple GET ou PUT)
  • Un chemin de requête HTTP
  • x-ms-date
  • Host
  • x-ms-content-sha256

Configurer l’en-tête d’autorisation

Effectuez les étapes suivantes pour construire l’en-tête d’autorisation.

Créer un script Python

Ouvrez Visual Studio Code ou un autre IDE ou éditeur de votre choix. Créez un nouveau fichier appelé sign_hmac_tutorial.py. Enregistrez ce fichier dans un dossier connu.

Ajout des importations nécessaires

Mettez à jour le script sign_hmac_tutorial.py avec le code suivant pour commencer.

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

Préparer les données pour la requête

Pour cet exemple, vous signez une demande pour créer une identité à l’aide de l’API d’authentification Communication Services (version 2021-03-07).

Ajoutez le code suivant au script sign_hmac_tutorial.py.

  • Remplacez resource_endpoint_name par votre valeur de nom de point de terminaison de ressource réelle. Vous trouverez cette valeur dans la section Vue d’ensemble de votre ressource Communication Services. C'est la valeur de Endpoint après https://.
  • Remplacez resource_endpoint_secret par votre valeur de secret de point de terminaison de ressource réelle. Vous trouverez cette valeur dans la section Clés de votre ressource Communication Services. Il s’agit de la valeur de Key, qui est primaire ou secondaire.
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")

Créer un hachage de contenu

Le hachage de contenu fait partie de votre signature HMAC. Utilisez le code suivant pour calculer le hachage de contenu. Vous pouvez ajouter cette méthode au 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

Calculer une signature

Utilisez le code suivant pour créer une méthode destinée à calculer votre signature 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

Obtenir un horodatage UTC actuel en fonction de la norme RFC1123

Utilisez le code suivant pour obtenir le format de date souhaité indépendamment des paramètres régionaux.

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)

Créer une chaîne d’en-tête d’autorisation

Maintenant, vous construisez la chaîne que vous ajoutez à votre en-tête d’autorisation.

  1. Préparez les valeurs des en-têtes à signer.
    1. Spécifiez l’horodatage actuel à l’aide du fuseau horaire UTC (Temps universel coordonné).
    2. Obtenez l'autorisation requise. Utilisez le nom d’hôte ou l’adresse IP DNS (Domain Name System) et le numéro de port.
    3. Calculer un hachage de contenu.
  2. Préparer une chaîne à signer.
  3. Calculer la signature.
  4. Concaténer la chaîne qui est utilisée dans l’en-tête d’autorisation.

Ajoutez le code suivant au script 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}"

Ajouter les en-têtes

Utilisez le code suivant pour ajouter les en-têtes obligatoires.

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"

Tester le client

Appelez le point de terminaison, puis vérifiez la réponse.

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

Nettoyer les ressources

Pour nettoyer et supprimer un abonnement Communication Services, supprimez la ressource ou le groupe de ressources. La suppression du groupe de ressources efface également les autres ressources qui y sont associées. Vous trouverez plus d’informations sur le nettoyage des ressources Azure Communication Services et le nettoyage des ressources Azure Functions.