Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Note
No todos los clientes pueden obtener certificados poP de mTLS porque esta característica está actualmente en versión preliminar privada.
El enlace de tokens de certificado (también conocido como Demostración de Posesión TLS Mutua - mTLS PoP) es una característica de seguridad avanzada que enlaza criptográficamente los tokens de acceso a un certificado específico X.509. RFC 8705 describe este enlace. El enlace garantiza que incluso si se intercepta un token, un atacante no puede usarlo sin posesión de la clave privada correspondiente.
Comprender cómo funciona la vinculación de tokens
En los pasos siguientes se describe el flujo de enlace de tokens desde la adquisición a través de la comprobación.
- Token Acquisition: al solicitar un token de acceso con el enlace de tokens habilitado, Microsoft Identity Web incluye la huella digital del certificado en la solicitud de token.
-
Asociación de tokens: el servidor de autorización inserta una afirmación (confirmación) en el token emitido que contiene la huella digital SHA-256 del certificado (
cnf) - Llamada API: el cliente presenta el token enlazado y el certificado al llamar a la API de bajada.
-
Comprobación: la API valida que el certificado presentado coincide con la referencia de certificado en la notificación 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
Revisión de las ventajas de seguridad
El enlace de tokens proporciona las siguientes ventajas para proteger las aplicaciones.
- Protección contra robo de tokens: los tokens robados son inútiles sin el certificado correspondiente.
- Prevención de ataques de reproducción: los tokens no se pueden reproducir desde distintos clientes
- Autenticación mejorada: combina "algo que tiene" (certificado) con flujos tradicionales de OAuth2
- arquitectura de Confianza cero: se alinea con los principios de zero trust mediante el enlace de credenciales a dispositivos específicos
Configuración del enlace de tokens
Configure tanto la aplicación cliente como el servidor de API para habilitar el enlace de tokens poP de mTLS.
Configuración de la aplicación cliente
Complete los pasos siguientes para configurar la aplicación cliente para el enlace de tokens.
1. Configurar las opciones de Microsoft Entra ID
En su appsettings.json, configure su configuración de Microsoft Entra, incluido el certificado.
{
"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. Configurar la API descendente con vinculación de tokens
Configure la sección de API descendente con el esquema de MTLS_POP protocolo:
{
"DownstreamApi": {
"BaseUrl": "https://api.contoso.com/",
"RelativePath": "api/data",
"ProtocolScheme": "MTLS_POP",
"RequestAppToken": true,
"Scopes": [ "api://your-api-scope/.default" ]
}
}
Propiedades de configuración importantes:
-
ProtocolScheme: debe establecerse en"MTLS_POP"para habilitar el enlace de tokens. -
RequestAppToken: debe sertrue(el enlace de tokens actualmente solo admite tokens de aplicación) -
Scopes: ámbitos de API necesarios para la llamada a la API descendente
3. Registrar servicios
Registre el servicio de API de bajada en el código de inicio de la aplicación. En el ejemplo siguiente se muestran los enfoques de aplicación de consola y 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"));
Configuración del servidor de API
La API de bajada debe validar tanto el token como el enlace de certificado. Este es un ejemplo completo:
1. Registrar controladores de autenticación
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. Implementación del controlador de autenticación poP de 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);
}
}
Uso del enlace de tokens en aplicaciones
En los ejemplos siguientes se muestra cómo integrar el enlace de tokens poP de mTLS en diferentes tipos de aplicación.
Llamar APIs desde una aplicación de consola o aplicación daemon
En el ejemplo siguiente se muestra una aplicación de consola o daemon que llama a una API downstream con la vinculación de tokens PoP de mTLS.
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; }
}
Llamada a las API desde una aplicación web de ASP.NET Core
En el ejemplo siguiente se muestra un controlador que llama a una API downstream con enlace de tokens PoP de MTLS.
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; }
}
Configuración de DownstreamApiOptions mediante programación
En el ejemplo siguiente se establecen las opciones poP de mTLS directamente en el código en lugar de los archivos de configuración.
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" };
});
}
}
Uso de MicrosoftIdentityMessageHandler con enlace de token
MicrosoftIdentityMessageHandler admite el enlace de tokens PoP de mTLS a través de los métodos de extensión AddMicrosoftIdentityMessageHandler. Cuando ProtocolScheme se establece en "MTLS_POP", el controlador adquiere automáticamente un token enlazado y envía solicitudes a través de un cliente HTTP configurado con mTLS.
Configurar opciones en línea
En el ejemplo siguiente se registra un cliente HTTP con la configuración de poP de mTLS insertada y se muestra su uso en un servicio.
// 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();
}
}
Carga de la configuración desde appsettings.json
También puede cargar la configuración de enlace de tokens desde el archivo de configuración.
appsettings.json:
{
"DownstreamApis": {
"SecureApi": {
"Scopes": ["api://secure-api/.default"],
"ProtocolScheme": "MTLS_POP",
"RequestAppToken": true
}
}
}
Program.cs: el código siguiente registra el cliente HTTP mediante la sección de configuración.
services.AddHttpClient("SecureApiClient", client =>
{
client.BaseAddress = new Uri("https://secure-api.example.com");
})
.AddMicrosoftIdentityMessageHandler(
configuration.GetSection("DownstreamApis:SecureApi"),
"SecureApi");
Aplicación del enlace de tokens por solicitud
Utiliza opciones por solicitud cuando algunas peticiones necesiten vinculación de tokens y otras no.
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();
}
Para obtener más información sobre MicrosoftIdentityMessageHandler, consulte la documentación de API personalizadas.
Creación de un HttpClient personalizado con el proveedor de encabezados de autorización
Use este enfoque para escenarios que requieren más control sobre las solicitudes HTTP. En el ejemplo siguiente se adquiere un encabezado de autorización enlazado y se crea un cliente HTTP configurado por 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);
}
}
Examen de la estructura del token
En los ejemplos siguientes se muestra cómo difieren los tokens estándar y enlazados.
Comparación de tokens estándar de OAuth2
Un token de OAuth2 estándar no contiene información de enlace de certificados.
{
"aud": "api://your-api",
"iss": "https://login.microsoftonline.com/tenant-id/",
"iat": 1234567890,
"exp": 1234571490,
"appid": "client-id",
"tid": "tenant-id"
}
Revisión de tokens PoP de mTLS con vinculación
Un token PoP de mTLS incluye la reclamación cnf que enlaza el token a un certificado específico.
{
"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"
}
}
La cnf afirmación (confirmación) contiene la huella digital SHA-256 del certificado, codificado en Base64-Url.
Descripción de las limitaciones actuales
Revise las siguientes restricciones antes de implementar la vinculación de tokens PoP de mTLS.
Solo se admiten tokens de aplicación
Actualmente, la vinculación de tokens solo admite tokens de solo aplicación. No se admiten tokens de usuario delegados.
Establecimiento del esquema de protocolo
La ProtocolScheme propiedad debe establecerse explícitamente en "MTLS_POP" para habilitar el enlace de tokens. Si no se establece, se usa la autenticación de portador estándar.
Cumplir los requisitos del certificado
- El certificado debe configurarse en
ClientCredentialsconSendX5cestablecido entrue. - El certificado debe ser accesible en el momento de la adquisición del token.
Solucionar problemas comunes
Use las instrucciones siguientes para diagnosticar y resolver problemas de enlace de tokens.
Resolución de problemas comunes
1. "Falta la notificación 'cnf' en el token"
Causa: el enlace de tokens no se configuró correctamente o el token es un token de portador estándar.
Solución: compruebe que ProtocolScheme está establecido en "MTLS_POP" y RequestAppToken es true.
{
"DownstreamApi": {
"ProtocolScheme": "MTLS_POP", // ensure this is set
"RequestAppToken": true
}
}
2. "Error de coincidencia de huella digital del certificado"
Causa: El certificado presentado a la API no coincide con el usado para la adquisición de tokens.
Solución:
- Compruebe que se usa el mismo certificado para la adquisición de tokens y las llamadas API.
- Verifique la configuración de carga de certificados en
ClientCredentials - Asegúrese de que el certificado no ha expirado o renovado
3. "Falta un certificado, que es necesario para el enlace de tokens"
Cause: no hay ningún certificado configurado en las configuraciones de Microsoft Entra.
Solución: agregue un certificado a su ClientCredentials configuración y establezca SendX5c a true.
{
"AzureAd": {
"ClientCredentials": [
{
"SourceType": "StoreWithDistinguishedName",
"CertificateStorePath": "CurrentUser/My",
"CertificateDistinguishedName": "CN=YourCertificate"
}
],
"SendX5c": true // required for token binding
}
}
4. "El enlace de tokens requiere la adquisición de tokens de aplicación habilitada"
Causa: RequestAppToken no está establecido en true.
Solución: Configure RequestAppToken a true en las opciones.
var options = new DownstreamApiOptions
{
ProtocolScheme = "MTLS_POP",
RequestAppToken = true, // must be true
};
Depuración de la vinculación de tokens
Use las técnicas siguientes para investigar los problemas de enlace de tokens.
Habilitación del registro detallado
Agregue la siguiente configuración para habilitar el registro de nivel de depuración para Microsoft. Identity.Web.
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.Identity.Web": "Debug"
}
}
}
Inspección de notificaciones de token
Utilice el siguiente código para enumerar todas las afirmaciones de un token y verificar la afirmación 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");
Comprobación de la huella digital del certificado
Use el código siguiente para calcular y mostrar la huella digital SHA-256 de un certificado para la comparación.
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}");
Siga las directrices de seguridad.
Aplique las siguientes prácticas de seguridad al implementar el enlace de tokens.
Administración de certificados de forma segura
- Store de forma segura: Usar Azure Key Vault o almacenes de certificados seguros
- Rotar regularmente: Implementar procedimientos de rotación de certificados
- Supervisión de la expiración: Configuración de alertas para la expiración del certificado
- Restringir el acceso: limitar quién puede acceder a las claves privadas del certificado
Protección de conexiones de red
- Requerir TLS 1.2 y versiones posteriores: asegúrese de que todas las conexiones usan versiones modernas de TLS.
- Validar certificados: implementar la validación de certificados adecuada en el servidor
- Uso de cifrados seguros: Configuración de conjuntos de cifrado seguros
Maneja tokens de forma segura
- Duración corta: use tokens de vida corta (recomendado: 1 hora)
- Almacenamiento adecuado: nunca almacenar ni exponer tokens
- Validar exhaustivamente: comprobación de todas las reclamaciones, expiración y vinculación
Seguimiento de los procedimientos recomendados
Tenga en cuenta las siguientes recomendaciones al implementar el enlace de tokens poP de mTLS.
- Usar siempre HTTPS: mTLS PoP requiere transporte seguro
- Use un certificado que almacene el material de clave privada en hardware, por ejemplo, en TPM: Usar seguridad de hardware en lugar de software para mejorar la protección
- Implementación de un manejo adecuado de errores: Manejar de manera eficiente los errores de certificado y token
- Supervisión de la expiración del certificado: Automatización de la renovación de certificados
- Uso de certificados independientes por entorno: desarrollo, almacenamiento provisional y certificados de producción
- Registrar eventos de seguridad: Rastrear errores de enlace de tokens y desajustes de certificados
- Prueba de la rotación de certificados: asegúrese de que la aplicación controla las actualizaciones de certificados.
- Documentar la configuración: Mantener la documentación clara de los requisitos de certificado
Contenido relacionado
- Documentación de Microsoft Identity Web
- Introducción a las API de bajada
- Documentación de API personalizadas
- credenciales de certificado de Microsoft Entra
- Autenticación de cliente de OAuth 2.0 Mutual-TLS
Exploración del código de ejemplo
Los ejemplos completos funcionales que demuestran la vinculación de tokens PoP mTLS están disponibles en el repositorio.
-
Aplicación cliente:
tests/DevApps/MtlsPop/MtlsPopClient -
Servidor de API web:
tests/DevApps/MtlsPop/MtlsPopWebApi
Estos ejemplos muestran:
- Completar la configuración de cliente y servidor
- Adquisición de tokens con vinculación de certificados
- Implementación del controlador de autenticación personalizada
- Validación de certificados y comprobación de huella digital