Scenario 9.1: Autenticazione client mTLS
Categoria: Autenticazione
Complessita: ⭐⭐⭐⭐ (Alta)
Prerequisiti: Certificati client e server
Tempo stimato: 20-30 minuti
Descrizione
Questo scenario descrive l'autenticazione Mutual TLS (mTLS), in cui sia il server che il client si autenticano reciprocamente con certificati.
Vantaggi rispetto all'autenticazione con password:
- Piu forte - Basata su crittografia
- Automatizzabile - Nessuna interazione utente
- Revocabile - Possibilita di revoca centralizzata
- Zero-Trust - Ogni richiesta e autenticata
Workflow
sequenceDiagram
participant Client
participant Server
Client->>Server: ClientHello
Server->>Client: ServerHello + ServerCert
Server->>Client: CertificateRequest
Client->>Server: ClientCert + CertificateVerify
Server->>Server: Validare certificato client
Server->>Client: Finished
Client->>Server: Finished
Note over Client,Server: Connessione mTLS stabilita
Esempio di codice: Server mTLS (ASP.NET Core)
using Microsoft.AspNetCore.Authentication.Certificate; using Microsoft.AspNetCore.Server.Kestrel.Https; var builder = WebApplication.CreateBuilder(args); // Configurare Kestrel per mTLS builder.WebHost.ConfigureKestrel(options => { options.ConfigureHttpsDefaults(https => { // Caricare certificato server https.ServerCertificate = new X509Certificate2( "server.pfx", "ServerPassword!"); // Richiedere certificato client https.ClientCertificateMode = ClientCertificateMode.RequireCertificate; // Validare certificato client https.ClientCertificateValidation = (cert, chain, errors) => { // Validazione personalizzata if (errors != SslPolicyErrors.None) { Console.WriteLine($"SSL Policy Errors: {errors}"); return false; } // Verificare propria CA var trustedRoots = new X509Certificate2Collection(); trustedRoots.Add(new X509Certificate2("root-ca.crt")); var customChain = new X509Chain(); customChain.ChainPolicy.CustomTrustStore.AddRange(trustedRoots); customChain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust; customChain.ChainPolicy.RevocationMode = X509RevocationMode.Online; return customChain.Build(cert); }; }); }); // Aggiungere Certificate Authentication builder.Services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme) .AddCertificate(options => { options.AllowedCertificateTypes = CertificateTypes.Chained; options.RevocationMode = X509RevocationMode.Online; options.Events = new CertificateAuthenticationEvents { OnCertificateValidated = context => { // Estrarre claims dal certificato var claims = new[] { new Claim(ClaimTypes.NameIdentifier, context.ClientCertificate.Subject), new Claim(ClaimTypes.Name, context.ClientCertificate.GetNameInfo(X509NameType.SimpleName, false)), new Claim("certificate_thumbprint", context.ClientCertificate.Thumbprint) }; context.Principal = new ClaimsPrincipal( new ClaimsIdentity(claims, context.Scheme.Name)); context.Success(); return Task.CompletedTask; }, OnAuthenticationFailed = context => { Console.WriteLine($"Auth failed: {context.Exception.Message}"); return Task.CompletedTask; } }; }); builder.Services.AddAuthorization(); var app = builder.Build(); app.UseAuthentication(); app.UseAuthorization(); app.MapGet("/api/protected", [Authorize] (HttpContext ctx) => { var subject = ctx.User.FindFirst(ClaimTypes.NameIdentifier)?.Value; return Results.Ok(new { message = "Authenticated", subject }); }); app.Run();
Esempio di codice: Client mTLS (HttpClient)
using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ; using var ctx = PqCryptoContext.Initialize(); // Caricare certificato e chiave client var clientCert = ctx.LoadCertificateWithPrivateKey( "client.crt.pem", "client.key.pem", "ClientPassword!" ); // HttpClientHandler con certificato client var handler = new HttpClientHandler { ClientCertificateOptions = ClientCertificateOption.Manual, ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { // Validare certificato server if (errors != SslPolicyErrors.None) { Console.WriteLine($"Server certificate error: {errors}"); // In produzione: return false; } return true; } }; // Aggiungere certificato client handler.ClientCertificates.Add(clientCert); using var httpClient = new HttpClient(handler); // Inviare richiesta var response = await httpClient.GetAsync("https://api.example.com/api/protected"); if (response.IsSuccessStatusCode) { var content = await response.Content.ReadAsStringAsync(); Console.WriteLine($"Response: {content}"); } else { Console.WriteLine($"Error: {response.StatusCode}"); }
Autorizzazione basata su certificato
public class CertificateAuthorizationHandler : AuthorizationHandler<CertificateRequirement> { protected override Task HandleRequirementAsync( AuthorizationHandlerContext context, CertificateRequirement requirement) { // Ottenere certificato dal Principal var thumbprint = context.User.FindFirst("certificate_thumbprint")?.Value; var subject = context.User.FindFirst(ClaimTypes.NameIdentifier)?.Value; if (string.IsNullOrEmpty(thumbprint)) { return Task.CompletedTask; } // Verificare se il certificato e autorizzato if (requirement.AllowedThumbprints.Contains(thumbprint) || requirement.AllowedSubjectPatterns.Any(p => Regex.IsMatch(subject, p))) { context.Succeed(requirement); } return Task.CompletedTask; } } public class CertificateRequirement : IAuthorizationRequirement { public HashSet<string> AllowedThumbprints { get; set; } = new(); public List<string> AllowedSubjectPatterns { get; set; } = new(); } // Registrazione builder.Services.AddAuthorization(options => { options.AddPolicy("ServiceAccounts", policy => policy.Requirements.Add(new CertificateRequirement { AllowedSubjectPatterns = new List<string> { @"^CN=.*\.svc\.cluster\.local$", // Kubernetes services @"^CN=service-[a-z]+$" // Named services } })); }); builder.Services.AddSingleton<IAuthorizationHandler, CertificateAuthorizationHandler>();
Nginx come Reverse Proxy mTLS
server { listen 443 ssl; server_name api.example.com; # Certificato server ssl_certificate /etc/nginx/ssl/server-chain.pem; ssl_certificate_key /etc/nginx/ssl/server.key.pem; # Autenticazione certificato client ssl_client_certificate /etc/nginx/ssl/ca-chain.pem; ssl_verify_client on; ssl_verify_depth 2; # TLS 1.3 ssl_protocols TLSv1.3; ssl_prefer_server_ciphers on; # OCSP Stapling ssl_stapling on; ssl_stapling_verify on; location / { # Passare info certificato client al backend proxy_set_header X-Client-Cert $ssl_client_cert; proxy_set_header X-Client-Verify $ssl_client_verify; proxy_set_header X-Client-S-DN $ssl_client_s_dn; proxy_pass http://backend:8080; } }
Requisiti mTLS specifici per settore
| Settore | Durata certificato | Revocation | Particolarita |
|---|---|---|---|
| Kubernetes | 1 anno | CRL | SPIFFE/SPIRE |
| Settore finanziario | 90 giorni | OCSP | Conforme PCI-DSS |
| Sanita | 1 anno | CRL + OCSP | Conforme DiGAV |
| IoT/SCADA | 5 anni | CRL | Capacita offline |
Scenari correlati
| Relazione | Scenario | Descrizione |
|---|---|---|
| Prerequisito | 3.2 Certificato client | Creare cert client |
| Correlato | 9.2 Smartcard Login | Token hardware |
| Correlato | 10.3 Deployment mTLS | Configurazione TLS |
« ← Panoramica autenticazione | ↑ Scenari | 9.2 Smartcard Login → »
Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional
Zuletzt geändert: il 30/01/2026 alle 00:16