Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Note
Non tutti i client possono ottenere certificati PoP mTLS perché questa funzionalità è attualmente in anteprima privata.
L'associazione di token del certificato (nota anche come mTLS PoP - Prova di Possesso TLS reciproco) è una funzionalità di sicurezza avanzata che associa in modo crittografico i token di accesso a un certificato X.509 specifico. RFC 8705 descrive questa associazione. Il binding garantisce che, anche se viene intercettato un token, un attaccante non può usarlo senza il possesso della chiave privata corrispondente.
Comprendere come funziona il binding di token
I passaggi seguenti descrivono il flusso di associazione di token dall'acquisizione tramite la verifica.
- Token Acquisition: Quando si richiede un token di accesso con l'associazione dei token abilitata, Microsoft Identity Web include l'impronta digitale del certificato nella richiesta di token.
-
Associazione di token: il server di autorizzazione incorpora un'attestazione
cnf(conferma) nel token rilasciato contenente l'identificazione personale SHA-256 del certificato (x5t#S256) - Chiamata API: il client presenta sia il token associato che il certificato quando si chiama l'API downstream
-
Verifica: l'API convalida che il certificato presentato corrisponda al riferimento al certificato nell'attestazione del
cnftoken
sequenceDiagram
participant Client
participant EntraID as Microsoft Entra ID
participant API
Client->>EntraID: Token request with certificate thumbprint
EntraID->>Client: Token with cnf claim (bound to certificate)
Client->>API: MTLS_POP token + Client certificate
API->>API: Validate token and certificate binding
API->>Client: Protected resource
Esaminare i vantaggi della sicurezza
L'associazione di token offre i vantaggi seguenti per la protezione delle applicazioni.
- Protezione dal furto di token: i token rubati sono inutili senza il certificato corrispondente
- Prevenzione degli attacchi di replay: i token non possono essere riprodotti da client diversi
- Autenticazione avanzata: combina "qualcosa di disponibile" (certificato) con i flussi OAuth2 tradizionali
- architettura Zero Trust: allinea ai principi di zero trust associando le credenziali a dispositivi specifici
Configurare l'associazione di token
Configurare sia l'applicazione client che il server API per abilitare l'associazione di token PoP mTLS.
Configurare l'applicazione client
Completare i passaggi seguenti per configurare l'applicazione client per l'associazione di token.
1. Configurare le impostazioni di Microsoft Entra ID
Nel tuo appsettings.json, configura le impostazioni di Microsoft Entra, incluso il certificato:
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "your-tenant-id",
"ClientId": "your-client-id",
"ClientCredentials": [
{
"SourceType": "StoreWithDistinguishedName",
"CertificateStorePath": "CurrentUser/My",
"CertificateDistinguishedName": "CN=YourCertificate"
}
],
"SendX5c": true
}
}
2. Configurare l'API downstream con l'associazione di token
Configurare la sezione API downstream con lo schema di protocollo MTLS_POP.
{
"DownstreamApi": {
"BaseUrl": "https://api.contoso.com/",
"RelativePath": "api/data",
"ProtocolScheme": "MTLS_POP",
"RequestAppToken": true,
"Scopes": [ "api://your-api-scope/.default" ]
}
}
Proprietà di configurazione importanti:
-
ProtocolScheme: deve essere impostato su"MTLS_POP"per abilitare l'associazione di token -
RequestAppToken: deve esseretrue(l'associazione di token supporta attualmente solo i token dell'applicazione) -
Scopes: ambiti API necessari per la chiamata API downstream
3. Registrare i servizi
Registrare il servizio API downstream nel codice di avvio dell'applicazione. L'esempio seguente mostra l'approccio dell'app console e quello di ASP.NET Core.
using Microsoft.Identity.Web;
var builder = WebApplication.CreateBuilder(args);
// Option 1: Using TokenAcquirerFactory (for console apps, background services)
var tokenAcquirerFactory = TokenAcquirerFactory.GetDefaultInstance();
tokenAcquirerFactory.Services.AddDownstreamApi(
"DownstreamApi",
tokenAcquirerFactory.Configuration.GetSection("DownstreamApi"));
var serviceProvider = tokenAcquirerFactory.Build();
// Option 2: Using ASP.NET Core DI (for web apps, web APIs)
builder.Services.AddAuthentication()
.AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"));
builder.Services.AddDownstreamApi(
"DownstreamApi",
builder.Configuration.GetSection("DownstreamApi"));
Configurare il server API
L'API downstream deve convalidare sia il token che l'associazione di certificati. Ecco un esempio completo:
1. Registrare i gestori di autenticazione
using Microsoft.Identity.Web;
var builder = WebApplication.CreateBuilder(args);
// Add standard JWT Bearer authentication
builder.Services.AddMicrosoftIdentityWebApiAuthentication(builder.Configuration);
// Add custom MTLS_POP authentication handler
builder.Services.AddAuthentication()
.AddScheme<AuthenticationSchemeOptions, MtlsPopAuthenticationHandler>(
"MTLS_POP",
options => { });
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
2. Implementare il gestore di autenticazione poP mTLS
using System.Security.Claims;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text.Encodings.Web;
using System.Text.Json;
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.JsonWebTokens;
using Microsoft.IdentityModel.Tokens;
public class MtlsPopAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
public const string ProtocolScheme = "MTLS_POP";
public MtlsPopAuthenticationHandler(
IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger,
UrlEncoder encoder)
: base(options, logger, encoder)
{
}
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
// 1. Extract the MTLS_POP authorization header
var authHeader = Request.Headers.Authorization.FirstOrDefault();
if (string.IsNullOrEmpty(authHeader) ||
!authHeader.StartsWith($"{ProtocolScheme} ", StringComparison.OrdinalIgnoreCase))
{
return AuthenticateResult.NoResult();
}
var authToken = authHeader.Substring($"{ProtocolScheme} ".Length).Trim();
try
{
// 2. Parse the JWT token
var handler = new JsonWebTokenHandler();
var token = handler.ReadJsonWebToken(authToken);
// 3. Extract the 'cnf' claim
var cnfClaim = token.Claims.FirstOrDefault(c => c.Type == "cnf");
if (cnfClaim == null)
{
return AuthenticateResult.Fail("Missing 'cnf' claim in MTLS_POP token");
}
// 4. Extract certificate thumbprint from cnf claim
var cnfJson = JsonDocument.Parse(cnfClaim.Value);
if (!cnfJson.RootElement.TryGetProperty("x5t#S256", out var x5tS256Element))
{
return AuthenticateResult.Fail("Missing 'x5t#S256' in cnf claim");
}
var expectedThumbprint = x5tS256Element.GetString();
// 5. Get client certificate from TLS connection
var clientCert = Context.Connection.ClientCertificate;
if (clientCert != null)
{
var actualThumbprint = GetCertificateThumbprint(clientCert);
// 6. Validate certificate binding
if (!string.Equals(actualThumbprint, expectedThumbprint,
StringComparison.OrdinalIgnoreCase))
{
return AuthenticateResult.Fail(
"Certificate thumbprint mismatch with cnf claim");
}
}
// 7. Create claims principal
var claims = token.Claims.Select(c => new Claim(c.Type, c.Value)).ToList();
var identity = new ClaimsIdentity(claims, ProtocolScheme);
var principal = new ClaimsPrincipal(identity);
var ticket = new AuthenticationTicket(principal, ProtocolScheme);
return AuthenticateResult.Success(ticket);
}
catch (Exception ex)
{
Logger.LogError(ex, "Error validating mTLS PoP token");
return AuthenticateResult.Fail($"Validation error: {ex.Message}");
}
}
private static string GetCertificateThumbprint(X509Certificate2 certificate)
{
using var sha256 = SHA256.Create();
var hash = sha256.ComputeHash(certificate.RawData);
return Base64UrlEncoder.Encode(hash);
}
}
Usare l'associazione di token nelle applicazioni
Gli esempi seguenti illustrano come integrare l'associazione di token PoP mTLS in diversi tipi di applicazione.
Chiamare le API da un'applicazione console o daemon
L'esempio seguente illustra un'applicazione da console o daemon che chiama un'API downstream con l'associazione di token mTLS PoP.
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Identity.Abstractions;
using Microsoft.Identity.Web;
public class Program
{
public static async Task Main(string[] args)
{
// Create and configure token acquirer
var tokenAcquirerFactory = TokenAcquirerFactory.GetDefaultInstance();
tokenAcquirerFactory.Services.AddDownstreamApi(
"SecureApi",
tokenAcquirerFactory.Configuration.GetSection("SecureApi"));
var serviceProvider = tokenAcquirerFactory.Build();
// Get IDownstreamApi instance
var downstreamApi = serviceProvider.GetRequiredService<IDownstreamApi>();
// Call API with mTLS PoP token
var response = await downstreamApi.GetForAppAsync<ApiResponse>("SecureApi");
Console.WriteLine($"Result: {response?.Data}");
}
}
public class ApiResponse
{
public string? Data { get; set; }
}
Chiamare le API da un'applicazione Web ASP.NET Core
L'esempio seguente illustra un controller che chiama un'API a valle con mTLS PoP token binding.
using Microsoft.AspNetCore.Mvc;
using Microsoft.Identity.Abstractions;
[ApiController]
[Route("api/[controller]")]
public class DataController : ControllerBase
{
private readonly IDownstreamApi _downstreamApi;
private readonly ILogger<DataController> _logger;
public DataController(
IDownstreamApi downstreamApi,
ILogger<DataController> logger)
{
_downstreamApi = downstreamApi;
_logger = logger;
}
[HttpGet]
public async Task<IActionResult> GetSecureData()
{
try
{
// Call downstream API with mTLS PoP token binding
var data = await _downstreamApi.GetForAppAsync<SecureData>(
"SecureApi");
return Ok(data);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to retrieve secure data");
return StatusCode(500, "Failed to retrieve data");
}
}
}
public class SecureData
{
public string? Id { get; set; }
public string? Value { get; set; }
}
Configurare DownstreamApiOptions a livello di codice
L'esempio seguente imposta le opzioni poP mTLS direttamente nel codice anziché nei file di configurazione.
using Microsoft.Identity.Abstractions;
using Microsoft.Identity.Web;
public class SecureApiService
{
private readonly IDownstreamApi _downstreamApi;
public SecureApiService(IDownstreamApi downstreamApi)
{
_downstreamApi = downstreamApi;
}
public async Task<T?> CallSecureApiAsync<T>(string endpoint) where T : class
{
return await _downstreamApi.GetForAppAsync<T>(
serviceName: null,
downstreamApiOptionsOverride: options =>
{
options.BaseUrl = "https://api.secure.com";
options.RelativePath = endpoint;
options.ProtocolScheme = "MTLS_POP";
options.RequestAppToken = true;
options.Scopes = new[] { "api://secure-api/.default" };
});
}
}
Usare MicrosoftIdentityMessageHandler con l'associazione di token
MicrosoftIdentityMessageHandler supporta l'associazione di token PoP mTLS tramite i metodi di estensione di AddMicrosoftIdentityMessageHandler. Quando ProtocolScheme è impostato su "MTLS_POP", il gestore acquisisce automaticamente un token associato e invia le richieste tramite un client HTTP configurato da mTLS.
Configurare le opzioni in linea
L'esempio seguente registra un client HTTP con la configurazione poP mTLS inline e ne mostra l'utilizzo in un servizio.
// Program.cs
services.AddHttpClient("MtlsPopClient", client =>
{
client.BaseAddress = new Uri("https://api.contoso.com");
})
.AddMicrosoftIdentityMessageHandler(options =>
{
options.Scopes.Add("api://contoso/.default");
options.ProtocolScheme = "MTLS_POP";
options.RequestAppToken = true;
});
// Usage in a service
public class SecureApiService
{
private readonly HttpClient _httpClient;
public SecureApiService(IHttpClientFactory factory)
{
_httpClient = factory.CreateClient("MtlsPopClient");
}
public async Task<string> GetSecureDataAsync()
{
// Authentication and mTLS certificate binding are automatic
var response = await _httpClient.GetAsync("/api/secure-data");
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
}
Caricare la configurazione da appsettings.json
È anche possibile caricare le impostazioni di associazione di token dal file di configurazione.
appsettings.json:
{
"DownstreamApis": {
"SecureApi": {
"Scopes": ["api://secure-api/.default"],
"ProtocolScheme": "MTLS_POP",
"RequestAppToken": true
}
}
}
Program.cs: il codice seguente registra il client HTTP usando la sezione di configurazione.
services.AddHttpClient("SecureApiClient", client =>
{
client.BaseAddress = new Uri("https://secure-api.example.com");
})
.AddMicrosoftIdentityMessageHandler(
configuration.GetSection("DownstreamApis:SecureApi"),
"SecureApi");
Applicare l'associazione di token per ciascuna richiesta
Usare le opzioni per richiesta quando alcune richieste richiedono l'associazione di token e altre non:
services.AddHttpClient("FlexibleClient")
.AddMicrosoftIdentityMessageHandler();
// In a service:
public async Task<string> CallWithTokenBindingAsync()
{
var request = new HttpRequestMessage(HttpMethod.Get, "https://api.contoso.com/secure")
.WithAuthenticationOptions(options =>
{
options.Scopes.Add("api://contoso/.default");
options.ProtocolScheme = "MTLS_POP";
options.RequestAppToken = true;
});
var response = await _httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
Per altre informazioni su MicrosoftIdentityMessageHandler, vedere la documentazione sulle API personalizzate.
Creare un HttpClient personalizzato con un provider di intestazioni di autorizzazione
Usare questo approccio per scenari che richiedono un maggiore controllo sulle richieste HTTP. L'esempio seguente acquisisce un'intestazione di autorizzazione associata e crea un client HTTP configurato da mTLS.
using Microsoft.Identity.Abstractions;
using System.Net.Http.Headers;
public class CustomApiClient
{
private readonly IAuthorizationHeaderProvider _authProvider;
private readonly IHttpClientFactory _httpClientFactory;
public CustomApiClient(
IAuthorizationHeaderProvider authProvider,
IHttpClientFactory httpClientFactory)
{
_authProvider = authProvider;
_httpClientFactory = httpClientFactory;
}
public async Task<string> CallApiWithCustomLogicAsync()
{
// Create downstream API options for mTLS PoP
var apiOptions = new DownstreamApiOptions
{
BaseUrl = "https://api.contoso.com",
ProtocolScheme = "MTLS_POP",
RequestAppToken = true,
Scopes = new[] { "api://contoso/.default" }
};
// Get authorization header with binding certificate info
var authResult = await (_authProvider as IBoundAuthorizationHeaderProvider)
?.CreateBoundAuthorizationHeaderAsync(apiOptions)!;
if (authResult.IsSuccess)
{
// Create HTTP client with certificate binding
var httpClient = authResult.Value.BindingCertificate != null
? CreateMtlsHttpClient(authResult.Value.BindingCertificate)
: _httpClientFactory.CreateClient();
// Set authorization header
httpClient.DefaultRequestHeaders.Authorization =
AuthenticationHeaderValue.Parse(authResult.Value.AuthorizationHeaderValue);
// Make API call
var response = await httpClient.GetAsync(
$"{apiOptions.BaseUrl}/api/endpoint");
return await response.Content.ReadAsStringAsync();
}
throw new InvalidOperationException("Failed to acquire token");
}
private HttpClient CreateMtlsHttpClient(X509Certificate2 certificate)
{
var handler = new HttpClientHandler();
handler.ClientCertificates.Add(certificate);
return new HttpClient(handler);
}
}
Esaminare la struttura dei token
Negli esempi seguenti viene illustrato come i token standard e associati differiscono.
Confrontare i token OAuth2 standard
Un token OAuth2 standard non contiene informazioni sull'associazione di certificati.
{
"aud": "api://your-api",
"iss": "https://login.microsoftonline.com/tenant-id/",
"iat": 1234567890,
"exp": 1234571490,
"appid": "client-id",
"tid": "tenant-id"
}
Esaminare i token PoP mTLS con l'associazione
Un token PoP mTLS include l'attestazione cnf che associa il token a un certificato specifico.
{
"aud": "api://your-api",
"iss": "https://login.microsoftonline.com/tenant-id/",
"iat": 1234567890,
"exp": 1234571490,
"appid": "client-id",
"tid": "tenant-id",
"cnf": {
"x5t#S256": "buc7x2HxS_hPnVJb9J5mwPr6jCw8Y_2LHDz-gp_-6KM"
}
}
L'asserzione cnf (conferma) contiene l'impronta digitale SHA-256 del certificato, codificata in Base64Url.
Comprendere le limitazioni correnti
Esaminare i vincoli seguenti prima di implementare l'associazione di token PoP mTLS.
Supporta solo token dell'applicazione
Attualmente, l'associazione di token supporta solo i token dell'applicazione (solo per app). I token delegati (utente) non sono supportati.
Impostare lo schema del protocollo
La ProtocolScheme proprietà deve essere impostata in modo esplicito su "MTLS_POP" per abilitare l'associazione di token. Se non è impostato, viene usata l'autenticazione Bearer standard.
Soddisfare i requisiti dei certificati
- Il certificato deve essere configurato in
ClientCredentialsconSendX5cimpostato sutrue - Il certificato deve essere accessibile in fase di acquisizione del token
Risolvere i problemi comuni
Usare le indicazioni seguenti per diagnosticare e risolvere i problemi di associazione di token.
Risolvere i problemi comuni
1. "Attestazione 'cnf' mancante nel token"
Causa: l'associazione di token non è stata configurata correttamente o il token è un token bearer standard.
Soluzione: verificare che ProtocolScheme sia impostato su "MTLS_POP" e RequestAppToken sia true.
{
"DownstreamApi": {
"ProtocolScheme": "MTLS_POP", // ensure this is set
"RequestAppToken": true
}
}
2. "Mancata corrispondenza dell'impronta digitale del certificato"
Causa: il certificato presentato all'API non corrisponde a quello usato per l'acquisizione di token.
Soluzione:
- Verificare che lo stesso certificato venga usato sia per l'acquisizione di token che per le chiamate API
- Controllare la configurazione del caricamento del certificato in
ClientCredentials - Verificare che il certificato non sia scaduto o rinnovato
3. "Manca un certificato, obbligatorio per l'associazione di token"
Cause: nessun certificato è configurato nelle impostazioni di Microsoft Entra.
Soluzione: aggiungere un certificato alla ClientCredentials configurazione e impostare SendX5c su true.
{
"AzureAd": {
"ClientCredentials": [
{
"SourceType": "StoreWithDistinguishedName",
"CertificateStorePath": "CurrentUser/My",
"CertificateDistinguishedName": "CN=YourCertificate"
}
],
"SendX5c": true // required for token binding
}
}
4. "L'associazione di token richiede l'acquisizione di token dell'app abilitata"
Causa: RequestAppToken non è impostato su true.
Soluzione: Imposta RequestAppToken a true nelle opzioni.
var options = new DownstreamApiOptions
{
ProtocolScheme = "MTLS_POP",
RequestAppToken = true, // must be true
};
Collegamento di token di debug
Usare le tecniche seguenti per analizzare i problemi di associazione di token.
Abilitare la registrazione dettagliata
Aggiungere la configurazione seguente per abilitare la registrazione a livello di debug per Microsoft. Identity.Web.
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.Identity.Web": "Debug"
}
}
}
Esaminare le attestazioni dei token
Usare il codice seguente per elencare tutte le attestazioni in un token e verificare la presenza dell'attestazione cnf .
var handler = new JsonWebTokenHandler();
var token = handler.ReadJsonWebToken(tokenString);
foreach (var claim in token.Claims)
{
Console.WriteLine($"{claim.Type}: {claim.Value}");
}
// Look for 'cnf' claim with x5t#S256
var cnfClaim = token.Claims.FirstOrDefault(c => c.Type == "cnf");
Verificare l'impronta digitale del certificato
Usare il codice seguente per calcolare e visualizzare l'impronta digitale SHA-256 di un certificato per il confronto.
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using Microsoft.IdentityModel.Tokens;
var cert = new X509Certificate2("path/to/cert.pfx", "password");
using var sha256 = SHA256.Create();
var hash = sha256.ComputeHash(cert.RawData);
var thumbprint = Base64UrlEncoder.Encode(hash);
Console.WriteLine($"Certificate thumbprint: {thumbprint}");
Seguire le linee guida per la sicurezza
Applicare le procedure di sicurezza seguenti quando si implementa l'associazione di token.
Gestire i certificati in modo sicuro
- Conservare in modo sicuro: utilizzare Azure Key Vault o archivi certificati protetti
- Ruotare regolarmente: implementare le procedure di rotazione dei certificati
- Monitorare la scadenza: configurare gli avvisi per la scadenza del certificato
- Limitare l'accesso: limitare chi può accedere alle chiavi private del certificato
Proteggere le connessioni di rete
- Richiedi TLS 1.2+: assicurarsi che tutte le connessioni usino versioni TLS moderne
- Convalida certificati: implementare la convalida corretta del certificato nel server
- Usare crittografie complesse: configurare suite di crittografia sicure
Gestire i token in modo sicuro
- Durate brevi: usare token di breve durata (scelta consigliata: 1 ora)
- Archiviazione appropriata: non registrare o esporre i token
- Convalidare accuratamente: controllare tutte le attestazioni, la scadenza e i vincoli
Seguire le migliori pratiche
Quando si implementa il binding del token PoP mTLS, tenete presente quanto segue.
- Usare sempre HTTPS: mTLS PoP richiede il trasporto sicuro
- Usare un certificato che archivia il materiale della chiave privata nell'hardware, ad esempio in TPM: Usare l'hardware sulla sicurezza software per una migliore protezione
- Implementare una corretta gestione degli errori: gestire correttamente gli errori di certificato e token
- Monitorare la scadenza del certificato: automatizzare il rinnovo del certificato
- Usare certificati separati per ambiente: certificati di sviluppo, gestione temporanea e produzione
- Registrare gli eventi di sicurezza: tenere traccia degli errori di associazione dei token e delle mancate corrispondenze del certificato
- Testare la rotazione dei certificati: assicurarsi che l'applicazione gestisca gli aggiornamenti dei certificati
- Documentare la configurazione: mantenere chiara la documentazione dei requisiti dei certificati
Contenuti correlati
- Documentazione di Microsoft Identity Web
- Panoramica della chiamata alle API downstream
- Documentazione sulle API personalizzate
- Microsoft Entra Credenziali del certificato
- Autenticazione mutuale TLS client OAuth 2.0
Esplorare il codice di esempio
Gli esempi di lavoro completi che illustrano l'associazione di token PoP mTLS sono disponibili nel repository:
-
Applicazione client:
tests/DevApps/MtlsPop/MtlsPopClient -
Server Web API:
tests/DevApps/MtlsPop/MtlsPopWebApi
Questi esempi illustrano:
- Completare la configurazione client e server
- Acquisizione di token con associazione di certificati
- Implementazione del gestore di autenticazione personalizzata
- Convalida del certificato e verifica dell'impronta digitale