Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Microsoft.AspNetCore.Authentication.Certificate bevat een implementatie die vergelijkbaar is met certificaatverificatie voor ASP.NET Core. Certificaatverificatie gebeurt op TLS-niveau voordat het ooit ASP.NET Core bereikt. Nauwkeuriger is deze functionaliteit een verificatiehandler waarmee het certificaat wordt gevalideerd en u vervolgens een gebeurtenis krijgt waarin u dat certificaat kunt oplossen in een ClaimsPrincipal.
U moetconfigure your server voor certificaatauthenticatie met IIS, Kestrel, Azure Web Apps of uw voorkeursoplossing.
In dit artikel wordt beschreven hoe u certificaatverificatie configureert in ASP.NET Core voor IIS en HTTP.sys, en biedt voorbeelden voor het aanroepen van verschillende methoden en het werken met eigenschappen.
Proxy- en load balancer-scenario's bekijken
Certificaatverificatie is een stateful scenario dat voornamelijk wordt gebruikt waarbij een proxy of load balancer geen verkeer tussen clients en servers verwerkt. Als een proxy of load balancer wordt gebruikt, werkt certificaatauthenticatie alleen als de proxy of load balancer:
- Verzorgt de authenticatie.
- Geeft de gebruikersverificatiegegevens door aan de app (bijvoorbeeld in een aanvraagheader), die op de verificatiegegevens reageert.
Een alternatief voor certificaatverificatie in omgevingen waarin proxy's en load balancers worden gebruikt, is Active Directory Federated Services (ADFS) met OpenID Connect (OIDC).
Aan de slag
Verkrijg een HTTPS-certificaat, pas dit toe en configureer uw server om certificaten te vereisen.
In de web-app:
Voeg een verwijzing toe naar het NuGet-pakket Microsoft.AspNetCore.Authentication.Certificate .
Roep in het bestand Program.cs de
builder.Services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme).AddCertificate(...);methode aan. Geef een gemachtigde op voor deOnCertificateValidatedgebeurtenishandler om eventuele aanvullende validatie uit te voeren op het clientcertificaat dat is verzonden met aanvragen. Zet die informatie om in eenClaimsPrincipalwaarde en stel deze in op decontext.Principaleigenschap.
Als de verificatie mislukt, retourneert deze handler een 403 (Forbidden) antwoord in plaats van een 401 (Unauthorized), zoals u zou verwachten. De handler retourneert een ander antwoord omdat wordt verwacht dat verificatie plaatsvindt tijdens de eerste TLS-verbinding. Tegen de tijd dat het de handler bereikt, is het te laat. U kunt de verbinding niet upgraden van een anonieme verbinding naar een verbinding met een certificaat.
De UseAuthentication methode is vereist om in te stellen HttpContext.User op een ClaimsPrincipal waarde die is gemaakt op basis van het certificaat. Voorbeeld:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthentication(
CertificateAuthenticationDefaults.AuthenticationScheme)
.AddCertificate();
var app = builder.Build();
app.UseAuthentication();
app.MapGet("/", () => "Hello World!");
app.Run();
In het voorgaande voorbeeld ziet u de standaardmethode voor het toevoegen van certificaatverificatie. De handler maakt een gebruikersprincipaal met behulp van de algemene certificaateigenschappen.
Certificaatvalidatie configureren
De CertificateAuthenticationOptions handler heeft een aantal ingebouwde validaties die de minimale validaties zijn die u op een certificaat moet uitvoeren. Elk van deze instellingen is standaard ingeschakeld. In de volgende secties wordt beschreven hoe u met de instellingen kunt werken.
AllowedCertificateTypes = Gekoppeld, Zelfondertekend, of Alle (Gekoppeld | Zelfondertekend)
Standaardwaarde: CertificateTypes.Chained
Met deze controle wordt gecontroleerd of alleen het juiste certificaattype is toegestaan. Als de app zelfondertekende certificaten gebruikt, moet deze optie worden ingesteld op CertificateTypes.All of CertificateTypes.SelfSigned.
ChainTrustValidatieMode
Standaardwaarde: X509ChainTrustMode.System
Het certificaat dat door de client wordt gepresenteerd, moet worden gekoppeld aan een vertrouwd basiscertificaat. Met deze controle bepaalt u welk vertrouwensarchief deze basiscertificaten bevat.
De handler maakt standaard gebruik van het vertrouwensarchief van het systeem. Als het gepresenteerde clientcertificaat moet worden gekoppeld aan een basiscertificaat dat niet wordt weergegeven in het systeemvertrouwensarchief, kunt u de optie instellen op X509ChainTrustMode.CustomRootTrust , zodat de handler de CustomTrustStore eigenschap gebruikt.
CustomTrustStore
Standaardwaarde: Leeg X509Certificate2Collection
Als de eigenschap van de handler is ingesteld op X509ChainTrustMode.CustomRootTrust, bevat dit X509Certificate2Collection object elk certificaat dat wordt gebruikt om het clientcertificaat te valideren tot aan een vertrouwde wortel, inclusief de vertrouwde wortel.
Wanneer de client een certificaat presenteert dat deel uitmaakt van een certificaatketen met meerdere niveaus, moet de CustomTrustStore eigenschap elk verlenend certificaat in de keten bevatten.
Certificaatgebruik valideren
Standaardwaarde: true
Met deze controle wordt gecontroleerd of het certificaat dat door de client wordt gepresenteerd, het uitgebreide sleutelgebruik (EKU) voor clientverificatie heeft, of dat er helemaal geen EKU's zijn. Zoals de specificaties zeggen, als er geen EKU is opgegeven, worden alle EKU's als geldig beschouwd.
BevestigGeldigheidsperiode
Standaardwaarde: true
Met deze controle wordt gecontroleerd of het certificaat binnen de geldigheidsperiode valt. Bij elke aanvraag zorgt de handler ervoor dat een certificaat dat geldig was toen het werd gepresenteerd, niet is verlopen tijdens de huidige sessie.
Intrekkingsflag
Standaardwaarde: X509RevocationFlag.ExcludeRoot
Een vlag die aangeeft welke certificaten in de keten worden gecontroleerd op intrekking.
Intrekkingscontroles worden alleen uitgevoerd wanneer het certificaat is gekoppeld aan een basiscertificaat.
Intrekkingsmodus
Standaardwaarde: X509RevocationMode.Online
Een vlag die aangeeft hoe intrekkingscontroles worden uitgevoerd.
Het specificeren van een onlinecontrole kan leiden tot een lange vertraging terwijl er contact wordt opgenomen met de certificaatinstantie.
Intrekkingscontroles worden alleen uitgevoerd wanneer het certificaat is gekoppeld aan een basiscertificaat.
Veelgestelde vragen: Kan ik mijn app zo configureren dat alleen een certificaat op bepaalde paden is vereist?
Deze aanpak is niet mogelijk. De certificaatuitwisseling wordt voltooid aan het begin van het HTTPS-gesprek. De bewerking wordt uitgevoerd door de server voordat de eerste aanvraag op die verbinding wordt ontvangen, zodat het niet mogelijk is om het bereik te bepalen op basis van aanvraagvelden.
Processhandler-gebeurtenissen
De handler heeft twee gebeurtenissen:
OnAuthenticationFailed: Wordt aangeroepen als er een uitzondering optreedt tijdens de verificatie en kunt u reageren.OnCertificateValidated: Aangeroepen nadat het certificaat geldig verklaard is, de validatie heeft doorstaan en er een standaard-principal is gemaakt. Met deze gebeurtenis kunt u uw eigen validatie uitvoeren en de principal uitbreiden of vervangen. Enkele voorbeelden:Bepalen of het certificaat bekend is bij uw services.
Uw eigen principal samenstellen, zoals in het volgende voorbeeld:
builder.Services.AddAuthentication( CertificateAuthenticationDefaults.AuthenticationScheme) .AddCertificate(options => { options.Events = new CertificateAuthenticationEvents { OnCertificateValidated = context => { var claims = new[] { new Claim( ClaimTypes.NameIdentifier, context.ClientCertificate.Subject, ClaimValueTypes.String, context.Options.ClaimsIssuer), new Claim( ClaimTypes.Name, context.ClientCertificate.Subject, ClaimValueTypes.String, context.Options.ClaimsIssuer) }; context.Principal = new ClaimsPrincipal( new ClaimsIdentity(claims, context.Scheme.Name)); context.Success(); return Task.CompletedTask; } }; });
Als het binnenkomende certificaat niet voldoet aan uw extra validatie, bel context.Fail("failure reason") met een foutreden.
Voor een betere functionaliteit, roep een service aan die is geregistreerd in dependency injection en verbinding maakt met een database of een ander type gebruikersopslag. Open de service met behulp van de context die is doorgegeven aan de gemachtigde. Bekijk het volgende voorbeeld:
builder.Services.AddAuthentication(
CertificateAuthenticationDefaults.AuthenticationScheme)
.AddCertificate(options =>
{
options.Events = new CertificateAuthenticationEvents
{
OnCertificateValidated = context =>
{
var validationService = context.HttpContext.RequestServices
.GetRequiredService<ICertificateValidationService>();
if (validationService.ValidateCertificate(context.ClientCertificate))
{
var claims = new[]
{
new Claim(
ClaimTypes.NameIdentifier,
context.ClientCertificate.Subject,
ClaimValueTypes.String, context.Options.ClaimsIssuer),
new Claim(
ClaimTypes.Name,
context.ClientCertificate.Subject,
ClaimValueTypes.String, context.Options.ClaimsIssuer)
};
context.Principal = new ClaimsPrincipal(
new ClaimsIdentity(claims, context.Scheme.Name));
context.Success();
}
return Task.CompletedTask;
}
};
});
Conceptueel is de validatie van het certificaat een autorisatieprobleem. U kunt bijvoorbeeld een controle toevoegen op een uitgever of duimafdruk in een autorisatiebeleid in plaats van in de OnCertificateValidated handler.
Configureer uw server zo dat certificaten vereist zijn.
In de volgende secties wordt beschreven hoe u uw server configureert om certificaten te vereisen voor een specifieke oplossing, waaronder Kestrel, IIS, Azure, aangepaste webproxy's en Azure Web Apps.
Kestrel
Configureer in het Kestrel als volgt:
var builder = WebApplication.CreateBuilder(args);
builder.Services.Configure<KestrelServerOptions>(options =>
{
options.ConfigureHttpsDefaults(options =>
options.ClientCertificateMode = ClientCertificateMode.RequireCertificate);
});
Opmerking
Wanneer een eindpunt wordt gemaakt door de Listen methode aan te roepen voordat de ConfigureHttpsDefaults methode wordt aangeroepen, worden de standaardwaarden niet toegepast op het eindpunt.
IIS
Voer de volgende stappen uit in IIS Manager:
- Selecteer uw site op het tabblad Verbindingen .
- Dubbelklik in het venster Functiesweergave op SSL-instellingen.
- Vink het selectievakje SSL vereisen aan.
- Selecteer Vereisen voor de optie Clientcertificaten.
Azure en aangepaste webproxy's
Zie de host en implementeer documentatie voor meer informatie over het configureren van de middleware voor het doorsturen van certificaten.
Certificaatverificatie in Azure Web Apps
Er is geen doorstuurconfiguratie vereist voor Azure. De Middleware voor het doorsturen van certificaten stelt de configuratie in.
Opmerking
Middleware voor het doorsturen van certificaten is vereist voor dit scenario.
Zie Tls/SSL-certificaten gebruiken in uw app-code (Azure documentatie) voor meer informatie.
Certificaatverificatie in aangepaste webproxy's
De AddCertificateForwarding methode wordt gebruikt om het volgende op te geven:
- De naam van de clientheader.
- Het certificaat laden (via de
HeaderConvertereigenschap).
In aangepaste webproxy's wordt het certificaat doorgegeven als een aangepaste aanvraagheader, bijvoorbeeld X-SSL-CERT. Als u het certificaat wilt gebruiken, configureert u het doorsturen van certificaten in het Program.cs-bestand :
builder.Services.AddCertificateForwarding(options =>
{
options.CertificateHeader = "X-SSL-CERT";
options.HeaderConverter = headerValue =>
{
X509Certificate2? clientCertificate = null;
if (!string.IsNullOrWhiteSpace(headerValue))
{
clientCertificate = new X509Certificate2(StringToByteArray(headerValue));
}
return clientCertificate!;
static byte[] StringToByteArray(string hex)
{
var numberChars = hex.Length;
var bytes = new byte[numberChars / 2];
for (int i = 0; i < numberChars; i += 2)
{
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
}
return bytes;
}
};
});
Als NGINX wordt gebruikt met de configuratie proxy_set_header ssl-client-cert $ssl_client_escaped_cert om reverse proxy voor de app uit te voeren, of als de app wordt geïmplementeerd op Kubernetes met behulp van NGINX Ingress, wordt het clientcertificaat aan de app doorgegeven in URL-gecodeerde vorm. Als u het certificaat wilt gebruiken, decodert u het als volgt:
builder.Services.AddCertificateForwarding(options =>
{
options.CertificateHeader = "ssl-client-cert";
options.HeaderConverter = (headerValue) =>
{
X509Certificate2? clientCertificate = null;
if (!string.IsNullOrWhiteSpace(headerValue))
{
clientCertificate = X509Certificate2.CreateFromPem(
WebUtility.UrlDecode(headerValue));
}
return clientCertificate!;
};
});
Voeg de middleware toe aan het Program.cs-bestand . De UseCertificateForwarding methode wordt aangeroepen voordat de aanroepen naar de UseAuthentication en UseAuthorization methoden worden aangeroepen:
var app = builder.Build();
app.UseCertificateForwarding();
app.UseAuthentication();
app.UseAuthorization();
Een afzonderlijke klasse kan worden gebruikt om validatielogica te implementeren. Omdat hetzelfde zelfondertekende certificaat in dit voorbeeld wordt gebruikt, moet u ervoor zorgen dat alleen uw certificaat kan worden gebruikt. Controleer of de vingerafdrukken van zowel het clientcertificaat als het servercertificaat overeenkomen. Anders kan elk certificaat worden gebruikt en voldoende zijn voor verificatie. Het certificaat wordt vervolgens in de AddCertificate methode gebruikt. U kunt hier ook de subject of de uitgever valideren als u tussenliggende of onderliggende certificaten gebruikt.
using System.Security.Cryptography.X509Certificates;
namespace CertAuthSample.Snippets;
public class SampleCertificateValidationService : ICertificateValidationService
{
public bool ValidateCertificate(X509Certificate2 clientCertificate)
{
// Don't hardcode passwords in production code.
// Use a certificate thumbprint or Azure Key Vault.
var expectedCertificate = new X509Certificate2(
Path.Combine("/path/to/pfx"), "1234");
return clientCertificate.Thumbprint == expectedCertificate.Thumbprint;
}
}
Een HttpClient implementeren met een certificaat en IHttpClientFactory
In het volgende voorbeeld wordt een clientcertificaat aan een HttpClientHandler toegevoegd met behulp van de ClientCertificates eigenschap van de handler. Deze handler kan vervolgens worden gebruikt in een benoemde instantie van een HttpClient met de ConfigurePrimaryHttpMessageHandler functie. Dit scenario is geconfigureerd in het Program.cs-bestand :
var clientCertificate =
new X509Certificate2(
Path.Combine(_environment.ContentRootPath, "sts_dev_cert.pfx"), "1234");
builder.Services.AddHttpClient("namedClient", c =>
{
}).ConfigurePrimaryHttpMessageHandler(() =>
{
var handler = new HttpClientHandler();
handler.ClientCertificates.Add(clientCertificate);
return handler;
});
De IHttpClientFactory kan vervolgens worden gebruikt om het benoemde exemplaar op te halen met behulp van de handler en het certificaat. De CreateClient methode met de naam van de client die is gedefinieerd in het bestand Program.cs wordt gebruikt om het exemplaar op te halen. De HTTP-aanvraag kan naar behoefte worden verzonden met behulp van de client:
public class SampleHttpService
{
private readonly IHttpClientFactory _httpClientFactory;
public SampleHttpService(IHttpClientFactory httpClientFactory)
=> _httpClientFactory = httpClientFactory;
public async Task<JsonDocument> GetAsync()
{
var httpClient = _httpClientFactory.CreateClient("namedClient");
var httpResponseMessage = await httpClient.GetAsync("https://example.com");
if (httpResponseMessage.IsSuccessStatusCode)
{
return JsonDocument.Parse(
await httpResponseMessage.Content.ReadAsStringAsync());
}
throw new ApplicationException($"Status code: {httpResponseMessage.StatusCode}");
}
}
Als het juiste certificaat naar de server wordt verzonden, worden de gegevens geretourneerd. Als er geen certificaat of het verkeerde certificaat wordt verzonden, retourneert de server een HTTP 403-statuscode.
Certificaten in PowerShell
Het maken van de certificaten is het moeilijkste onderdeel van het instellen van deze stroom. U kunt een basiscertificaat maken met behulp van de New-SelfSignedCertificate PowerShell-cmdlet. Wanneer u het certificaat maakt, gebruikt u een sterk wachtwoord. Het is belangrijk om de KeyUsageProperty parameter en de KeyUsage parameter toe te voegen, zoals wordt weergegeven in de voorbeelden.
Basiscertificeringsinstantie maken
De volgende code laat zien hoe u een certificeringsinstantie (CA) aan de root maakt.
New-SelfSignedCertificate -DnsName "root_ca_dev_damienbod.com", "root_ca_dev_damienbod.com" -CertStoreLocation "cert:\LocalMachine\My" -NotAfter (Get-Date).AddYears(20) -FriendlyName "root_ca_dev_damienbod.com" -KeyUsageProperty All -KeyUsage CertSign, CRLSign, DigitalSignature
$mypwd = ConvertTo-SecureString -String "1234" -Force -AsPlainText
Get-ChildItem -Path cert:\localMachine\my\"The thumbprint..." | Export-PfxCertificate -FilePath C:\git\root_ca_dev_damienbod.pfx -Password $mypwd
Export-Certificate -Cert cert:\localMachine\my\"The thumbprint..." -FilePath root_ca_dev_damienbod.crt
Opmerking
De -DnsName parameterwaarde moet overeenkomen met het implementatiedoel van de app. Bijvoorbeeld 'localhost' voor ontwikkeling.
Installeren in de vertrouwde basis
Het basiscertificaat moet worden vertrouwd op uw hostsysteem. Alleen basiscertificaten die door een certificeringsinstantie zijn gemaakt, worden standaard vertrouwd. Zie
Een tussenliggend certificaat gebruiken
Er kan nu een tussenliggend certificaat worden gemaakt op basis van het basiscertificaat. Deze benadering is niet vereist voor alle use cases, maar mogelijk moet u veel certificaten maken of groepen certificaten activeren of uitschakelen. De TextExtension parameter is vereist om de padlengte in te stellen in de basisbeperkingen van het certificaat.
Het tussenliggende certificaat kan vervolgens worden toegevoegd aan het vertrouwde tussenliggende certificaat in het Windows-hostsysteem.
$mypwd = ConvertTo-SecureString -String "1234" -Force -AsPlainText
$parentcert = ( Get-ChildItem -Path cert:\LocalMachine\My\"The thumbprint of the root..." )
New-SelfSignedCertificate -certstorelocation cert:\localmachine\my -dnsname "intermediate_dev_damienbod.com" -Signer $parentcert -NotAfter (Get-Date).AddYears(20) -FriendlyName "intermediate_dev_damienbod.com" -KeyUsageProperty All -KeyUsage CertSign, CRLSign, DigitalSignature -TextExtension @("2.5.29.19={text}CA=1&pathlength=1")
Get-ChildItem -Path cert:\localMachine\my\"The thumbprint..." | Export-PfxCertificate -FilePath C:\git\AspNetCoreCertificateAuth\Certs\intermediate_dev_damienbod.pfx -Password $mypwd
Export-Certificate -Cert cert:\localMachine\my\"The thumbprint..." -FilePath intermediate_dev_damienbod.crt
Een onderliggend certificaat maken op basis van een tussenliggend certificaat
Er kan een kindercertificaat worden gemaakt op basis van het tussenliggende certificaat. Dit kindcertificaat is de eindentiteit. U hoeft geen subcertificaten aan te maken.
$parentcert = ( Get-ChildItem -Path cert:\LocalMachine\My\"The thumbprint from the Intermediate certificate..." )
New-SelfSignedCertificate -certstorelocation cert:\localmachine\my -dnsname "child_a_dev_damienbod.com" -Signer $parentcert -NotAfter (Get-Date).AddYears(20) -FriendlyName "child_a_dev_damienbod.com"
$mypwd = ConvertTo-SecureString -String "1234" -Force -AsPlainText
Get-ChildItem -Path cert:\localMachine\my\"The thumbprint..." | Export-PfxCertificate -FilePath C:\git\AspNetCoreCertificateAuth\Certs\child_a_dev_damienbod.pfx -Password $mypwd
Export-Certificate -Cert cert:\localMachine\my\"The thumbprint..." -FilePath child_a_dev_damienbod.crt
Kindcertificaat maken van rootcertificaat
Een kindcertificaat kan ook rechtstreeks vanuit het basiscertificaat worden gemaakt.
$rootcert = ( Get-ChildItem -Path cert:\LocalMachine\My\"The thumbprint from the root cert..." )
New-SelfSignedCertificate -certstorelocation cert:\localmachine\my -dnsname "child_a_dev_damienbod.com" -Signer $rootcert -NotAfter (Get-Date).AddYears(20) -FriendlyName "child_a_dev_damienbod.com"
$mypwd = ConvertTo-SecureString -String "1234" -Force -AsPlainText
Get-ChildItem -Path cert:\localMachine\my\"The thumbprint..." | Export-PfxCertificate -FilePath C:\git\AspNetCoreCertificateAuth\Certs\child_a_dev_damienbod.pfx -Password $mypwd
Export-Certificate -Cert cert:\localMachine\my\"The thumbprint..." -FilePath child_a_dev_damienbod.crt
Voorbeeld: basiscertificaat - tussenliggend certificaat - certificaat
In het volgende voorbeeld ziet u de configuratie van de basis-CA, het tussenliggende certificaat en het onderliggende certificaat:
$mypwdroot = ConvertTo-SecureString -String "1234" -Force -AsPlainText
$mypwd = ConvertTo-SecureString -String "1234" -Force -AsPlainText
New-SelfSignedCertificate -DnsName "root_ca_dev_damienbod.com", "root_ca_dev_damienbod.com" -CertStoreLocation "cert:\LocalMachine\My" -NotAfter (Get-Date).AddYears(20) -FriendlyName "root_ca_dev_damienbod.com" -KeyUsageProperty All -KeyUsage CertSign, CRLSign, DigitalSignature
Get-ChildItem -Path cert:\localMachine\my\0C89639E4E2998A93E423F919B36D4009A0F9991 | Export-PfxCertificate -FilePath C:\git\root_ca_dev_damienbod.pfx -Password $mypwdroot
Export-Certificate -Cert cert:\localMachine\my\0C89639E4E2998A93E423F919B36D4009A0F9991 -FilePath root_ca_dev_damienbod.crt
$rootcert = ( Get-ChildItem -Path cert:\LocalMachine\My\0C89639E4E2998A93E423F919B36D4009A0F9991 )
New-SelfSignedCertificate -certstorelocation cert:\localmachine\my -dnsname "child_a_dev_damienbod.com" -Signer $rootcert -NotAfter (Get-Date).AddYears(20) -FriendlyName "child_a_dev_damienbod.com" -KeyUsageProperty All -KeyUsage CertSign, CRLSign, DigitalSignature -TextExtension @("2.5.29.19={text}CA=1&pathlength=1")
Get-ChildItem -Path cert:\localMachine\my\BA9BF91ED35538A01375EFC212A2F46104B33A44 | Export-PfxCertificate -FilePath C:\git\AspNetCoreCertificateAuth\Certs\child_a_dev_damienbod.pfx -Password $mypwd
Export-Certificate -Cert cert:\localMachine\my\BA9BF91ED35538A01375EFC212A2F46104B33A44 -FilePath child_a_dev_damienbod.crt
$parentcert = ( Get-ChildItem -Path cert:\LocalMachine\My\BA9BF91ED35538A01375EFC212A2F46104B33A44 )
New-SelfSignedCertificate -certstorelocation cert:\localmachine\my -dnsname "child_b_from_a_dev_damienbod.com" -Signer $parentcert -NotAfter (Get-Date).AddYears(20) -FriendlyName "child_b_from_a_dev_damienbod.com"
Get-ChildItem -Path cert:\localMachine\my\141594A0AE38CBBECED7AF680F7945CD51D8F28A | Export-PfxCertificate -FilePath C:\git\AspNetCoreCertificateAuth\Certs\child_b_from_a_dev_damienbod.pfx -Password $mypwd
Export-Certificate -Cert cert:\localMachine\my\141594A0AE38CBBECED7AF680F7945CD51D8F28A -FilePath child_b_from_a_dev_damienbod.crt
Wanneer u de basis-, tussen- of onderliggende certificaten gebruikt, kunnen de certificaten worden gevalideerd met behulp van de vingerafdruk of PublicKey, indien nodig:
using System.Security.Cryptography.X509Certificates;
namespace CertAuthSample.Snippets;
public class SampleCertificateThumbprintsValidationService : ICertificateValidationService
{
private readonly string[] validThumbprints = new[]
{
"141594A0AE38CBBECED7AF680F7945CD51D8F28A",
"0C89639E4E2998A93E423F919B36D4009A0F9991",
"BA9BF91ED35538A01375EFC212A2F46104B33A44"
};
public bool ValidateCertificate(X509Certificate2 clientCertificate)
=> validThumbprints.Contains(clientCertificate.Thumbprint);
}
Validatieresultaten van cachecertificaten
.NET 5 en latere versies ondersteunen de mogelijkheid om caching van validatieresultaten in te schakelen. De caching verbetert de prestaties van certificaatverificatie aanzienlijk omdat validatie een dure bewerking is.
Certificaatverificatie schakelt standaard caching uit. Als u caching wilt inschakelen, roept u de AddCertificateCache methode aan in het Program.cs-bestand :
builder.Services.AddAuthentication(
CertificateAuthenticationDefaults.AuthenticationScheme)
.AddCertificate()
.AddCertificateCache(options =>
{
options.CacheSize = 1024;
options.CacheEntryExpiration = TimeSpan.FromMinutes(2);
});
De standaard caching-implementatie slaat resultaten op in het geheugen. U kunt uw eigen cache opgeven door ICertificateValidationCache te implementeren en het te registreren via afhankelijkheidsinjectie. Bijvoorbeeld: services.AddSingleton<ICertificateValidationCache, YourCache>().
Optionele clientcertificaten gebruiken
Deze sectie bevat informatie voor apps die een subset van de app met een certificaat moeten beveiligen. Voor een Razor pagina of controller in de app zijn bijvoorbeeld clientcertificaten vereist. Dit scenario biedt enkele uitdagingen:
- Clientcertificaten zijn een TLS-functie, geen HTTP-functie.
- Clientcertificaten worden onderhandeld per verbinding en meestal aan het begin van de verbinding voordat er HTTP-gegevens beschikbaar zijn.
Er zijn twee benaderingen voor het implementeren van optionele clientcertificaten:
- Optie 1: Gebruik afzonderlijke hostnamen (SNI) en omleiding. Hoewel deze optie meer werk omvat om te configureren, wordt de aanpak aanbevolen omdat deze werkt in de meeste omgevingen en protocollen.
- Optie 2: Heronderhandeling tijdens een HTTP-aanvraag. Deze benadering heeft verschillende beperkingen en wordt niet aanbevolen.
Afzonderlijke hosts (SNI)
Aan het begin van de verbinding is alleen de SNI-† (Server Name Indication) bekend. Clientcertificaten kunnen per hostnaam worden geconfigureerd, zodat de ene host de certificaten vereist en een andere niet.
Stel binding in voor het domein en subdomein.
Stel bijvoorbeeld bindingen in op
contoso.comenmyClient.contoso.com. Voor decontoso.comhost is geen clientcertificaat vereist, maarmyClient.contoso.comwel.Zie de volgende bronnen voor meer informatie:
IIS
HTTP.sys
.NET 5 en hoger biedt meer handige ondersteuning voor het omleiden om optionele clientcertificaten te verkrijgen. Zie het voorbeeld van optionele certificaten voor meer informatie.
Voor aanvragen naar de web-app waarvoor een clientcertificaat is vereist en die geen clientcertificaat hebben, moet u omleiden naar dezelfde pagina met behulp van het met het clientcertificaat beveiligde subdomein.
Bijvoorbeeld omleiden naar
myClient.contoso.com/requestedPage. Omdat de aanvraag naarmyClient.contoso.com/requestedPageeen andere hostnaam heeft dancontoso.com/requestedPage, brengt de client een andere verbinding tot stand en wordt het clientcertificaat verstrekt.Zie Inleiding tot autorisatie in ASP.NET Core voor meer informatie.
† Server Name Indication (SNI) is een TLS-extensie die wordt gebruikt om een virtueel domein op te nemen als onderdeel van SSL-onderhandeling. Deze methode betekent effectief dat de virtuele domeinnaam of een hostnaam kan worden gebruikt om het eindpunt van het netwerk te identificeren.
TLS-heronderhandeling
TLS-heronderhandeling is een proces waarmee de client en server de versleutelingsvereisten voor een afzonderlijke verbinding opnieuw kunnen beoordelen, inclusief het aanvragen van een clientcertificaat als dat nog niet eerder is opgegeven. TLS-heronderhandeling is een beveiligingsrisico en wordt niet aanbevolen omdat:
- In HTTP/1.1 moet de server eerst HTTP-gegevens in de vlucht bufferen of gebruiken, zoals POST-aanvraaginstanties om ervoor te zorgen dat de verbinding duidelijk is voor de heronderhandeling. Anders kan de heronderhandeling stoppen met reageren of mislukken.
- HTTP/2 en HTTP/3 verbieden expliciet heronderhandeling.
- Er zijn beveiligingsrisico's verbonden aan heronderhandeling. TLS 1.3 heeft de heronderhandeling van de hele verbinding verwijderd en vervangen door een nieuwe extensie voor alleen het aanvragen van een clientcertificaat nadat de verbinding is gestart. Dit mechanisme wordt weergegeven via dezelfde API's en is nog steeds onderhevig aan de eerdere beperkingen van buffering en HTTP-protocolversies.
De implementatie en configuratie van deze functie variëren per server- en frameworkversie, zoals beschreven in de volgende secties.
IIS
IIS beheert namens u de onderhandeling van het clientcertificaat. Een subsectie van de toepassing kan de SslRequireCert optie inschakelen om te onderhandelen over het clientcertificaat voor deze aanvragen. Zie Configuratie in de IIS-documentatie voor meer informatie.
IIS buffert automatisch alle aanvraagbodygegevens tot een geconfigureerde groottelimiet voordat opnieuw wordt onderhandeld. Aanvragen die de limiet overschrijden, worden geweigerd met een 413-antwoord. Deze limiet is standaard ingesteld op 48 kB en kan worden geconfigureerd door de eigenschap uploadReadAheadSize in te stellen.
HttpSys
HttpSys heeft twee instellingen waarmee de onderhandeling van het clientcertificaat wordt gecontroleerd, en ze moeten beide worden ingesteld. De eerste bevindt zich in het netsh.exe bestand onder http add sslcert clientcertnegotiation=enable/disable. Met deze vlag wordt aangegeven of het clientcertificaat aan het begin van een verbinding moet worden onderhandeld. Stel de waarde in op disable voor optionele clientcertificaten. Zie het http add sslcert parametergebruik in de netsh-documenten voor meer informatie.
De andere parameter is de ClientCertificateMethod eigenschap. Wanneer ingesteld op AllowRenegotation, kan het clientcertificaat tijdens een aanvraag opnieuw worden onderhandeld.
Opmerking
De toepassing moet de hoofdtekstgegevens van de aanvraag bufferen of gebruiken voordat de heronderhandeling wordt uitgevoerd. Anders kan de aanvraag onresponsief worden.
Een toepassing kan eerst de ClientCertificate eigenschap controleren om te zien of het certificaat beschikbaar is. Als deze niet beschikbaar is, moet u ervoor zorgen dat de aanvraagbody wordt gebruikt voordat u de GetClientCertificateAsync methode aanroept om er een te onderhandelen.
GetClientCertificateAsync kan een null-certificaat retourneren als de client weigert er een op te geven.
Opmerking
Het gedrag van de eigenschap ClientCertificate is gewijzigd in .NET 6. Zie GitHub probleem #466 voor meer informatie.
Kestrel
Kestrel beheert de afhandeling van client-certificaten met de eigenschap ClientCertificateMode.
.NET 6 en hoger biedt de optie DelayCertificate voor de eigenschap ClientCertificateMode. Wanneer deze optie is ingesteld, kan een app de ClientCertificate eigenschap controleren om te zien of het certificaat beschikbaar is. Als deze niet beschikbaar is, moet u ervoor zorgen dat de aanvraagbody wordt verwerkt voordat u de GetClientCertificateAsync methode aanroept om een overeenkomst te onderhandelen.
GetClientCertificateAsync kan een null-certificaat retourneren als de client weigert er een op te geven.
Opmerking
De toepassing moet de hoofdtekstgegevens van de aanvraag bufferen of gebruiken voordat de heronderhandeling wordt uitgevoerd.
GetClientCertificateAsync Anders kan de uitzondering InvalidOperationException worden gegenereerd: Clientstream moet worden leeggezogen voordat opnieuw wordt onderhandeld.
Als u de TLS-instellingen via een programma configureert per SNI-hostnaam, roept u de UseHttps overload (.NET 6 of hoger) aan die een TlsHandshakeCallbackOptions-klasseobject gebruikt. Met deze optie wordt de heronderhandeling van het clientcertificaat via de AllowDelayedClientCertificateNegotation eigenschap bepaald. Zie de methode ListenOptionsHttpsExtensions.UseHttps voor meer informatie.
Microsoft.AspNetCore.Authentication.Certificate bevat een implementatie die vergelijkbaar is met certificaatverificatie voor ASP.NET Core. Certificaatverificatie vindt plaats op het TLS-niveau, dat ruim voor ASP.NET Core gebeurt. Nauwkeuriger valideert deze verificatiehandler het certificaat en geeft u een gebeurtenis waar u het certificaat kunt oplossen naar een ClaimsPrincipal waarde.
Configureer uw server voor certificaatverificatie, of het nu IIS, KestrelAzure Web Apps of wat u ook gebruikt.
Scenario's voor proxy en load balancer
Certificaatverificatie is een stateful scenario dat voornamelijk wordt gebruikt waarbij een proxy of load balancer geen verkeer tussen clients en servers verwerkt. Als een proxy of load balancer wordt gebruikt, werkt certificaatauthenticatie alleen als de proxy of load balancer:
- Verzorgt de authenticatie.
- Geeft de gebruikersverificatiegegevens door aan de app (bijvoorbeeld in een aanvraagheader), die op de verificatiegegevens reageert.
Een alternatief voor certificaatverificatie in omgevingen waarin proxy's en load balancers worden gebruikt, is Active Directory Federated Services (ADFS) met OpenID Connect (OIDC).
Aan de slag
Verkrijg een HTTPS-certificaat, pas dit toe en configureer uw server om certificaten te vereisen.
Voeg in uw web-app een verwijzing toe naar het pakket Microsoft.AspNetCore.Authentication.Certificate . Roep vervolgens in de Startup.ConfigureServices methode services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme).AddCertificate(...); uw opties aan en geef een gemachtigde op om OnCertificateValidated eventuele aanvullende validatie uit te voeren op het clientcertificaat dat is verzonden met aanvragen. Zet deze informatie om in een ClaimsPrincipal en stel deze in op de context.Principal eigenschap.
Als de verificatie mislukt, retourneert deze handler een 403 (Forbidden) antwoord in plaats van een 401 (Unauthorized), zoals u zou verwachten. De redenering is dat de verificatie moet plaatsvinden tijdens de eerste TLS-verbinding. Tegen de tijd dat het de handler bereikt, is het te laat. U kunt de verbinding niet upgraden van een anonieme verbinding naar een verbinding met een certificaat.
Voeg ook app.UseAuthentication(); toe in de Startup.Configure methode. Anders wordt het HttpContext.User niet ingesteld op ClaimsPrincipal dat is gemaakt van het certificaat. Voorbeeld:
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(
CertificateAuthenticationDefaults.AuthenticationScheme)
.AddCertificate()
// Adding an ICertificateValidationCache results in certificate auth caching the results.
// The default implementation uses a memory cache.
.AddCertificateCache();
// All other service configuration
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseAuthentication();
// All other app configuration
}
In het voorgaande voorbeeld ziet u de standaardmethode voor het toevoegen van certificaatverificatie. De handler maakt een gebruikersprincipaal met behulp van de algemene certificaateigenschappen.
Certificaatvalidatie configureren
De CertificateAuthenticationOptions handler heeft een aantal ingebouwde validaties die de minimale validaties zijn die u op een certificaat moet uitvoeren. Elk van deze instellingen is standaard ingeschakeld.
AllowedCertificateTypes = Gekoppeld, Zelfondertekend, of Alle (Gekoppeld | Zelfondertekend)
Standaardwaarde: CertificateTypes.Chained
Met deze controle wordt gecontroleerd of alleen het juiste certificaattype is toegestaan. Als de app zelfondertekende certificaten gebruikt, moet deze optie worden ingesteld op CertificateTypes.All of CertificateTypes.SelfSigned.
Certificaatgebruik valideren
Standaardwaarde: true
Met deze controle wordt gecontroleerd of het certificaat dat door de client wordt gepresenteerd, het uitgebreide sleutelgebruik (EKU) voor clientverificatie heeft, of dat er helemaal geen EKU's zijn. Zoals de specificaties zeggen, als er geen EKU is opgegeven, worden alle EKU's als geldig beschouwd.
BevestigGeldigheidsperiode
Standaardwaarde: true
Met deze controle wordt gecontroleerd of het certificaat binnen de geldigheidsperiode valt. Bij elke aanvraag zorgt de handler ervoor dat een certificaat dat geldig was toen het werd gepresenteerd, niet is verlopen tijdens de huidige sessie.
Intrekkingsflag
Standaardwaarde: X509RevocationFlag.ExcludeRoot
Een vlag die aangeeft welke certificaten in de keten worden gecontroleerd op intrekking.
Intrekkingscontroles worden alleen uitgevoerd wanneer het certificaat is gekoppeld aan een basiscertificaat.
Intrekkingsmodus
Standaardwaarde: X509RevocationMode.Online
Een vlag die aangeeft hoe intrekkingscontroles worden uitgevoerd.
Het specificeren van een onlinecontrole kan leiden tot een lange vertraging terwijl er contact wordt opgenomen met de certificaatinstantie.
Intrekkingscontroles worden alleen uitgevoerd wanneer het certificaat is gekoppeld aan een basiscertificaat.
Kan ik mijn app zo configureren dat alleen een certificaat op bepaalde paden is vereist?
Dit is niet mogelijk. Onthoud dat de certificaatuitwisseling wordt uitgevoerd aan het begin van het HTTPS-gesprek. Dit wordt gedaan door de server voordat de eerste aanvraag op die verbinding wordt ontvangen, zodat het niet mogelijk is om het bereik te bepalen op basis van aanvraagvelden.
Handler-gebeurtenissen
De handler heeft twee gebeurtenissen:
-
OnAuthenticationFailed: Wordt aangeroepen als er een uitzondering optreedt tijdens de verificatie en kunt u reageren. -
OnCertificateValidated: Aangeroepen nadat het certificaat succesvol gevalideerd is en er een standaardprincipal is gemaakt. Met deze gebeurtenis kunt u uw eigen validatie uitvoeren en de principal uitbreiden of vervangen. Voorbeelden hiervan zijn:Bepalen of het certificaat bekend is bij uw services.
Uw eigen principal samenstellen. Bekijk het volgende voorbeeld in
Startup.ConfigureServices:services.AddAuthentication( CertificateAuthenticationDefaults.AuthenticationScheme) .AddCertificate(options => { options.Events = new CertificateAuthenticationEvents { OnCertificateValidated = context => { var claims = new[] { new Claim( ClaimTypes.NameIdentifier, context.ClientCertificate.Subject, ClaimValueTypes.String, context.Options.ClaimsIssuer), new Claim(ClaimTypes.Name, context.ClientCertificate.Subject, ClaimValueTypes.String, context.Options.ClaimsIssuer) }; context.Principal = new ClaimsPrincipal( new ClaimsIdentity(claims, context.Scheme.Name)); context.Success(); return Task.CompletedTask; } }; });
Als het binnenkomende certificaat niet voldoet aan uw extra validatie, geef dan een foutreden door aan context.Fail("failure reason").
Voor echte functionaliteit wilt u waarschijnlijk een service aanroepen die is geregistreerd bij afhankelijkheidsinjectie die verbinding maakt met een database of een ander type gebruikersarchief. Open uw service met behulp van de context die is doorgegeven aan uw gemachtigde. Bekijk het volgende voorbeeld in Startup.ConfigureServices:
services.AddAuthentication(
CertificateAuthenticationDefaults.AuthenticationScheme)
.AddCertificate(options =>
{
options.Events = new CertificateAuthenticationEvents
{
OnCertificateValidated = context =>
{
var validationService =
context.HttpContext.RequestServices
.GetRequiredService<ICertificateValidationService>();
if (validationService.ValidateCertificate(
context.ClientCertificate))
{
var claims = new[]
{
new Claim(
ClaimTypes.NameIdentifier,
context.ClientCertificate.Subject,
ClaimValueTypes.String,
context.Options.ClaimsIssuer),
new Claim(
ClaimTypes.Name,
context.ClientCertificate.Subject,
ClaimValueTypes.String,
context.Options.ClaimsIssuer)
};
context.Principal = new ClaimsPrincipal(
new ClaimsIdentity(claims, context.Scheme.Name));
context.Success();
}
return Task.CompletedTask;
}
};
});
Conceptueel is de validatie van het certificaat een autorisatieprobleem. Het toevoegen van een controle op bijvoorbeeld een uitgever of vingerafdruk in een autorisatiebeleid, in plaats van binnen OnCertificateValidated, is volledig acceptabel.
Configureer uw server zo dat certificaten vereist zijn.
Kestrel
Program.cs Configureer Kestrelals volgt in:
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args)
{
return Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
webBuilder.ConfigureKestrel(o =>
{
o.ConfigureHttpsDefaults(o =>
o.ClientCertificateMode = ClientCertificateMode.RequireCertificate);
});
});
}
Opmerking
Eindpunten die zijn gemaakt door Listenaan te roepen voordatConfigureHttpsDefaults worden aangeroepen, worden de standaardwaarden niet toegepast.
IIS
Voer de volgende stappen uit in IIS Manager:
- Selecteer uw site op het tabblad Verbindingen .
- Dubbelklik op de optie SSL-instellingen in het venster Functiesweergave .
- Vink het selectievakje SSL vereisen aan en selecteer de optie Vereisen in de sectie Clientcertificaten.
Azure en aangepaste webproxy's
Raadpleeg de host- en implementatiedocumentatie voor het configureren van de middleware voor het doorsturen van certificaten.
Certificaatverificatie gebruiken in Azure Web Apps
Er is geen doorstuurconfiguratie vereist voor Azure. De doorstuurconfiguratie wordt ingesteld door de Middleware voor het doorsturen van certificaten.
Opmerking
Middleware voor het doorsturen van certificaten is vereist voor dit scenario.
Zie Een TLS/SSL-certificaat gebruiken in uw code in Azure App Service (Documentatie voor Azure) voor meer informatie.
Certificaatverificatie gebruiken in aangepaste webproxy's
De AddCertificateForwarding methode wordt gebruikt om het volgende op te geven:
- De naam van de clientheader.
- Hoe het certificaat moet worden geladen (met behulp van de
HeaderConvertereigenschap).
In aangepaste webproxy's wordt het certificaat doorgegeven als een aangepaste aanvraagheader, bijvoorbeeld X-SSL-CERT. Als u het wilt gebruiken, configureert u het doorsturen van certificaten in Startup.ConfigureServices:
public void ConfigureServices(IServiceCollection services)
{
services.AddCertificateForwarding(options =>
{
options.CertificateHeader = "X-SSL-CERT";
options.HeaderConverter = (headerValue) =>
{
X509Certificate2 clientCertificate = null;
if(!string.IsNullOrWhiteSpace(headerValue))
{
byte[] bytes = StringToByteArray(headerValue);
clientCertificate = new X509Certificate2(bytes);
}
return clientCertificate;
};
});
}
private static byte[] StringToByteArray(string hex)
{
int NumberChars = hex.Length;
byte[] bytes = new byte[NumberChars / 2];
for (int i = 0; i < NumberChars; i += 2)
{
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
}
return bytes;
}
nl-NL: Als de app omgekeerd geproxy'd wordt door NGINX met de configuratie proxy_set_header ssl-client-cert $ssl_client_escaped_cert of geïmplementeerd op Kubernetes met behulp van NGINX Ingress, wordt het clientcertificaat doorgegeven aan de app in URL-gecodeerde vorm. Als u het certificaat wilt gebruiken, decodert u het als volgt:
In Startup.ConfigureServices (Startup.cs):
services.AddCertificateForwarding(options =>
{
options.CertificateHeader = "ssl-client-cert";
options.HeaderConverter = (headerValue) =>
{
X509Certificate2 clientCertificate = null;
if (!string.IsNullOrWhiteSpace(headerValue))
{
string certPem = WebUtility.UrlDecode(headerValue);
clientCertificate = X509Certificate2.CreateFromPem(certPem);
}
return clientCertificate;
};
});
De Startup.Configure methode voegt vervolgens de middleware toe.
UseCertificateForwarding wordt aangeroepen vóór de aanroepen naar UseAuthentication en UseAuthorization:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
app.UseRouting();
app.UseCertificateForwarding();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
Een afzonderlijke klasse kan worden gebruikt om validatielogica te implementeren. Omdat hetzelfde zelfondertekende certificaat in dit voorbeeld wordt gebruikt, moet u ervoor zorgen dat alleen uw certificaat kan worden gebruikt. Controleer of de vingerafdrukken van zowel het clientcertificaat als het servercertificaat overeenkomen, anders kan elk certificaat worden gebruikt en is voldoende om te verifiëren. Dit wordt gebruikt in de AddCertificate methode. U kunt hier ook het onderwerp of de uitgever valideren als u intermediaire of subcertificaten gebruikt.
using System.IO;
using System.Security.Cryptography.X509Certificates;
namespace AspNetCoreCertificateAuthApi
{
public class MyCertificateValidationService
{
public bool ValidateCertificate(X509Certificate2 clientCertificate)
{
// Do not hardcode passwords in production code
// Use thumbprint or key vault
var cert = new X509Certificate2(
Path.Combine("sts_dev_cert.pfx"), "1234");
if (clientCertificate.Thumbprint == cert.Thumbprint)
{
return true;
}
return false;
}
}
}
Een HttpClient implementeren met behulp van een certificaat en de HttpClientHandler
De HttpClientHandler kan rechtstreeks in de constructor van de HttpClient klasse worden toegevoegd. Er moet voorzichtig te werk worden gegaan bij het maken van exemplaren van de HttpClient. Het HttpClient certificaat wordt vervolgens met elke aanvraag verzonden.
private async Task<JsonDocument> GetApiDataUsingHttpClientHandler()
{
var cert = new X509Certificate2(Path.Combine(_environment.ContentRootPath, "sts_dev_cert.pfx"), "1234");
var handler = new HttpClientHandler();
handler.ClientCertificates.Add(cert);
var client = new HttpClient(handler);
var request = new HttpRequestMessage()
{
RequestUri = new Uri("https://localhost:44379/api/values"),
Method = HttpMethod.Get,
};
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
var responseContent = await response.Content.ReadAsStringAsync();
var data = JsonDocument.Parse(responseContent);
return data;
}
throw new ApplicationException($"Status code: {response.StatusCode}, Error: {response.ReasonPhrase}");
}
Een HttpClient implementeren met behulp van een certificaat en een httpclient met de naam IHttpClientFactory
In het volgende voorbeeld wordt een clientcertificaat aan een HttpClientHandler toegevoegd met behulp van de ClientCertificates eigenschap van de handler. Deze handler kan vervolgens worden gebruikt in een benoemd exemplaar van een HttpClient met behulp van de ConfigurePrimaryHttpMessageHandler methode. Dit is ingesteld in Startup.ConfigureServices:
var clientCertificate =
new X509Certificate2(
Path.Combine(_environment.ContentRootPath, "sts_dev_cert.pfx"), "1234");
services.AddHttpClient("namedClient", c =>
{
}).ConfigurePrimaryHttpMessageHandler(() =>
{
var handler = new HttpClientHandler();
handler.ClientCertificates.Add(clientCertificate);
return handler;
});
De IHttpClientFactory kan vervolgens worden gebruikt om het benoemde exemplaar op te halen met behulp van de handler en het certificaat. De CreateClient methode met de naam van de client die in de Startup klasse is gedefinieerd, wordt gebruikt om het exemplaar op te halen. De HTTP-aanvraag kan naar behoefte worden verzonden met behulp van de client.
private readonly IHttpClientFactory _clientFactory;
public ApiService(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
private async Task<JsonDocument> GetApiDataWithNamedClient()
{
var client = _clientFactory.CreateClient("namedClient");
var request = new HttpRequestMessage()
{
RequestUri = new Uri("https://localhost:44379/api/values"),
Method = HttpMethod.Get,
};
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
var responseContent = await response.Content.ReadAsStringAsync();
var data = JsonDocument.Parse(responseContent);
return data;
}
throw new ApplicationException($"Status code: {response.StatusCode}, Error: {response.ReasonPhrase}");
}
Als het juiste certificaat naar de server wordt verzonden, worden de gegevens geretourneerd. Als er geen certificaat of het verkeerde certificaat wordt verzonden, wordt een HTTP 403-statuscode geretourneerd.
Certificaten maken in PowerShell
Het maken van de certificaten is het moeilijkste onderdeel van het instellen van deze stroom. U kunt een basiscertificaat maken met behulp van de New-SelfSignedCertificate PowerShell-cmdlet. Wanneer u het certificaat maakt, gebruikt u een sterk wachtwoord. Het is belangrijk om de KeyUsageProperty parameter en de KeyUsage parameter toe te voegen, zoals wordt weergegeven.
Basis-CA maken
New-SelfSignedCertificate -DnsName "root_ca_dev_damienbod.com", "root_ca_dev_damienbod.com" -CertStoreLocation "cert:\LocalMachine\My" -NotAfter (Get-Date).AddYears(20) -FriendlyName "root_ca_dev_damienbod.com" -KeyUsageProperty All -KeyUsage CertSign, CRLSign, DigitalSignature
$mypwd = ConvertTo-SecureString -String "1234" -Force -AsPlainText
Get-ChildItem -Path cert:\localMachine\my\"The thumbprint..." | Export-PfxCertificate -FilePath C:\git\root_ca_dev_damienbod.pfx -Password $mypwd
Export-Certificate -Cert cert:\localMachine\my\"The thumbprint..." -FilePath root_ca_dev_damienbod.crt
Opmerking
De -DnsName parameterwaarde moet overeenkomen met het implementatiedoel van de app. Bijvoorbeeld 'localhost' voor ontwikkeling.
Installeren in de vertrouwde basis
Het rootcertificaat moet op uw hostsysteem vertrouwd worden. Een basiscertificaat dat niet is gemaakt door een certificeringsinstantie, wordt niet standaard vertrouwd. Zie deze vraag voor informatie over het vertrouwen van het basiscertificaat in Windows.
Tussenliggend certificaat
Er kan nu een tussenliggend certificaat worden gemaakt op basis van het basiscertificaat. Dit is niet vereist voor alle use cases, maar mogelijk moet u veel certificaten maken of groepen certificaten activeren of uitschakelen. De TextExtension parameter is vereist om de padlengte in te stellen in de basisbeperkingen van het certificaat.
Het tussenliggende certificaat kan vervolgens worden toegevoegd aan het vertrouwde tussenliggende certificaat in het Windows-hostsysteem.
$mypwd = ConvertTo-SecureString -String "1234" -Force -AsPlainText
$parentcert = ( Get-ChildItem -Path cert:\LocalMachine\My\"The thumbprint of the root..." )
New-SelfSignedCertificate -certstorelocation cert:\localmachine\my -dnsname "intermediate_dev_damienbod.com" -Signer $parentcert -NotAfter (Get-Date).AddYears(20) -FriendlyName "intermediate_dev_damienbod.com" -KeyUsageProperty All -KeyUsage CertSign, CRLSign, DigitalSignature -TextExtension @("2.5.29.19={text}CA=1&pathlength=1")
Get-ChildItem -Path cert:\localMachine\my\"The thumbprint..." | Export-PfxCertificate -FilePath C:\git\AspNetCoreCertificateAuth\Certs\intermediate_dev_damienbod.pfx -Password $mypwd
Export-Certificate -Cert cert:\localMachine\my\"The thumbprint..." -FilePath intermediate_dev_damienbod.crt
Een onderliggend certificaat maken op basis van een tussenliggend certificaat
Er kan een kindercertificaat worden gemaakt op basis van het tussenliggende certificaat. Dit is de eindentiteit die geen kindcertificaten hoeft te maken.
$parentcert = ( Get-ChildItem -Path cert:\LocalMachine\My\"The thumbprint from the Intermediate certificate..." )
New-SelfSignedCertificate -certstorelocation cert:\localmachine\my -dnsname "child_a_dev_damienbod.com" -Signer $parentcert -NotAfter (Get-Date).AddYears(20) -FriendlyName "child_a_dev_damienbod.com"
$mypwd = ConvertTo-SecureString -String "1234" -Force -AsPlainText
Get-ChildItem -Path cert:\localMachine\my\"The thumbprint..." | Export-PfxCertificate -FilePath C:\git\AspNetCoreCertificateAuth\Certs\child_a_dev_damienbod.pfx -Password $mypwd
Export-Certificate -Cert cert:\localMachine\my\"The thumbprint..." -FilePath child_a_dev_damienbod.crt
Kindcertificaat maken van rootcertificaat
Een kindcertificaat kan ook rechtstreeks vanuit het basiscertificaat worden gemaakt.
$rootcert = ( Get-ChildItem -Path cert:\LocalMachine\My\"The thumbprint from the root cert..." )
New-SelfSignedCertificate -certstorelocation cert:\localmachine\my -dnsname "child_a_dev_damienbod.com" -Signer $rootcert -NotAfter (Get-Date).AddYears(20) -FriendlyName "child_a_dev_damienbod.com"
$mypwd = ConvertTo-SecureString -String "1234" -Force -AsPlainText
Get-ChildItem -Path cert:\localMachine\my\"The thumbprint..." | Export-PfxCertificate -FilePath C:\git\AspNetCoreCertificateAuth\Certs\child_a_dev_damienbod.pfx -Password $mypwd
Export-Certificate -Cert cert:\localMachine\my\"The thumbprint..." -FilePath child_a_dev_damienbod.crt
Voorbeeld rootcertificaat - tussenliggend certificaat - certificaat
$mypwdroot = ConvertTo-SecureString -String "1234" -Force -AsPlainText
$mypwd = ConvertTo-SecureString -String "1234" -Force -AsPlainText
New-SelfSignedCertificate -DnsName "root_ca_dev_damienbod.com", "root_ca_dev_damienbod.com" -CertStoreLocation "cert:\LocalMachine\My" -NotAfter (Get-Date).AddYears(20) -FriendlyName "root_ca_dev_damienbod.com" -KeyUsageProperty All -KeyUsage CertSign, CRLSign, DigitalSignature
Get-ChildItem -Path cert:\localMachine\my\0C89639E4E2998A93E423F919B36D4009A0F9991 | Export-PfxCertificate -FilePath C:\git\root_ca_dev_damienbod.pfx -Password $mypwdroot
Export-Certificate -Cert cert:\localMachine\my\0C89639E4E2998A93E423F919B36D4009A0F9991 -FilePath root_ca_dev_damienbod.crt
$rootcert = ( Get-ChildItem -Path cert:\LocalMachine\My\0C89639E4E2998A93E423F919B36D4009A0F9991 )
New-SelfSignedCertificate -certstorelocation cert:\localmachine\my -dnsname "child_a_dev_damienbod.com" -Signer $rootcert -NotAfter (Get-Date).AddYears(20) -FriendlyName "child_a_dev_damienbod.com" -KeyUsageProperty All -KeyUsage CertSign, CRLSign, DigitalSignature -TextExtension @("2.5.29.19={text}CA=1&pathlength=1")
Get-ChildItem -Path cert:\localMachine\my\BA9BF91ED35538A01375EFC212A2F46104B33A44 | Export-PfxCertificate -FilePath C:\git\AspNetCoreCertificateAuth\Certs\child_a_dev_damienbod.pfx -Password $mypwd
Export-Certificate -Cert cert:\localMachine\my\BA9BF91ED35538A01375EFC212A2F46104B33A44 -FilePath child_a_dev_damienbod.crt
$parentcert = ( Get-ChildItem -Path cert:\LocalMachine\My\BA9BF91ED35538A01375EFC212A2F46104B33A44 )
New-SelfSignedCertificate -certstorelocation cert:\localmachine\my -dnsname "child_b_from_a_dev_damienbod.com" -Signer $parentcert -NotAfter (Get-Date).AddYears(20) -FriendlyName "child_b_from_a_dev_damienbod.com"
Get-ChildItem -Path cert:\localMachine\my\141594A0AE38CBBECED7AF680F7945CD51D8F28A | Export-PfxCertificate -FilePath C:\git\AspNetCoreCertificateAuth\Certs\child_b_from_a_dev_damienbod.pfx -Password $mypwd
Export-Certificate -Cert cert:\localMachine\my\141594A0AE38CBBECED7AF680F7945CD51D8F28A -FilePath child_b_from_a_dev_damienbod.crt
Wanneer u de basis-, tussen- of onderliggende certificaten gebruikt, kunnen de certificaten naar behoefte worden gevalideerd met behulp van de vingerafdruk of PublicKey.
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography.X509Certificates;
namespace AspNetCoreCertificateAuthApi
{
public class MyCertificateValidationService
{
public bool ValidateCertificate(X509Certificate2 clientCertificate)
{
return CheckIfThumbprintIsValid(clientCertificate);
}
private bool CheckIfThumbprintIsValid(X509Certificate2 clientCertificate)
{
var listOfValidThumbprints = new List<string>
{
"141594A0AE38CBBECED7AF680F7945CD51D8F28A",
"0C89639E4E2998A93E423F919B36D4009A0F9991",
"BA9BF91ED35538A01375EFC212A2F46104B33A44"
};
if (listOfValidThumbprints.Contains(clientCertificate.Thumbprint))
{
return true;
}
return false;
}
}
}
Opslaan in cache van certificaatvalidatie
.NET 5 of nieuwere versies ondersteunen de mogelijkheid om caching van validatieresultaten in te schakelen. De caching verbetert de prestaties van certificaatverificatie aanzienlijk, omdat validatie een dure bewerking is.
Certificaatverificatie schakelt standaard caching uit. Om caching in te schakelen, roept u AddCertificateCache aan in Startup.ConfigureServices:
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(
CertificateAuthenticationDefaults.AuthenticationScheme)
.AddCertificate()
.AddCertificateCache(options =>
{
options.CacheSize = 1024;
options.CacheEntryExpiration = TimeSpan.FromMinutes(2);
});
}
De standaard caching-implementatie slaat resultaten op in het geheugen. U kunt uw eigen cache opgeven door ICertificateValidationCache te implementeren en het te registreren via afhankelijkheidsinjectie. Bijvoorbeeld: services.AddSingleton<ICertificateValidationCache, YourCache>().
Optionele clientcertificaten
Deze sectie bevat informatie voor apps die een subset van de app met een certificaat moeten beveiligen. Voor een Razor pagina of controller in de app zijn bijvoorbeeld clientcertificaten vereist. Dit brengt uitdagingen met zich mee als clientcertificaten:
- Zijn een TLS-functie, geen HTTP-functie.
- Wordt onderhandeld per verbinding en meestal aan het begin van de verbinding voordat er HTTP-gegevens beschikbaar zijn.
Er zijn twee benaderingen voor het implementeren van optionele clientcertificaten:
- Gebruik afzonderlijke hostnamen (SNI) en doorsturen. Hoewel er meer werk nodig is om te configureren, wordt dit aanbevolen omdat dit werkt in de meeste omgevingen en protocollen.
- Heronderhandeling tijdens een HTTP-aanvraag. Dit heeft verschillende beperkingen en wordt niet aanbevolen.
Afzonderlijke hosts (SNI)
Aan het begin van de verbinding is alleen de SNI-† (Server Name Indication) bekend. Clientcertificaten kunnen per hostnaam worden geconfigureerd, zodat de ene host deze vereist en een andere niet.
- Binding instellen voor het domein en subdomein:
- Stel bijvoorbeeld bindingen in op
contoso.comenmyClient.contoso.com. Voor decontoso.comhost is geen clientcertificaat vereist, maarmyClient.contoso.comwel. - Zie voor meer informatie:
- Stel bijvoorbeeld bindingen in op
.NET 5 of hoger voegt handigere ondersteuning toe voor het omleiden om optionele clientcertificaten te verkrijgen. Zie het voorbeeld van optionele certificaten voor meer informatie.
- Voor aanvragen voor de web-app waarvoor een clientcertificaat vereist is maar niet aanwezig is:
- Omleiden naar dezelfde pagina met behulp van het met het clientcertificaat beveiligde subdomein.
- Bijvoorbeeld omleiden naar
myClient.contoso.com/requestedPage. Omdat de aanvraag naarmyClient.contoso.com/requestedPageeen andere hostnaam heeft dancontoso.com/requestedPage, brengt de client een andere verbinding tot stand en wordt het clientcertificaat verstrekt. - Zie Inleiding tot autorisatie in ASP.NET Core voor meer informatie.
† Server Name Indication (SNI) is een TLS-extensie om een virtueel domein op te nemen als onderdeel van SSL-onderhandeling. Dit betekent dat de virtuele domeinnaam of een hostnaam effectief kan worden gebruikt om het netwerkeindpunt te identificeren.
Heronderhandeling
TLS-heronderhandeling is een proces waarmee de client en server de versleutelingsvereisten voor een afzonderlijke verbinding opnieuw kunnen beoordelen, inclusief het aanvragen van een clientcertificaat als dat nog niet eerder is opgegeven. TLS-heronderhandeling is een beveiligingsrisico en wordt niet aanbevolen omdat:
- In HTTP/1.1 moet de server eerst HTTP-gegevens bufferen of verwerken die in de doorgang zijn, zoals POST-verzoeklichamen om ervoor te zorgen dat de verbinding vrij is voor de heronderhandeling. Anders kan de heronderhandeling stoppen met reageren of mislukken.
- HTTP/2 en HTTP/3 verbieden expliciet heronderhandeling.
- Er zijn beveiligingsrisico's verbonden aan heronderhandeling. TLS 1.3 heeft de heronderhandeling van de hele verbinding verwijderd en vervangen door een nieuwe extensie voor alleen het aanvragen van een clientcertificaat nadat de verbinding is gestart. Dit mechanisme wordt weergegeven via dezelfde API's en is nog steeds onderhevig aan de eerdere beperkingen van buffering en HTTP-protocolversies.
De implementatie en configuratie van deze functie variëren per server- en frameworkversie.
IIS
IIS beheert namens u de onderhandeling van het clientcertificaat. Een subsectie van de toepassing kan de SslRequireCert optie inschakelen om te onderhandelen over het clientcertificaat voor deze aanvragen. Zie Configuratie in de IIS-documentatie voor meer informatie.
IIS buffert automatisch eventuele aanvraagbodygegevens tot een geconfigureerde groottelimiet voordat opnieuw wordt onderhandeld. Aanvragen die de limiet overschrijden, worden geweigerd met een 413-antwoord. Deze limiet is standaard ingesteld op 48 kB en kan worden geconfigureerd door de uploadReadAheadSize in te stellen.
HttpSys
HttpSys heeft twee instellingen die de onderhandeling van het clientcertificaat regelen en beide moeten worden ingesteld. De eerste bevindt zich in netsh.exe onder http add sslcert clientcertnegotiation=enable/disable. Deze vlag geeft aan of het clientcertificaat moet worden onderhandeld aan het begin van een verbinding en moet worden ingesteld disable op voor optionele clientcertificaten. Zie de netsh-documenten voor meer informatie.
De andere instelling is ClientCertificateMethod. Wanneer ingesteld op AllowRenegotation, kan het clientcertificaat tijdens een aanvraag opnieuw worden onderhandeld.
NOTITIE De toepassing moet de hoofdtekstgegevens van de aanvraag bufferen of gebruiken voordat de heronderhandeling wordt uitgevoerd, anders reageert de aanvraag mogelijk niet meer.
Er is een bekend probleem waarbij het inschakelen AllowRenegotation ervoor kan zorgen dat de heronderhandeling synchroon plaatsvindt bij het openen van de ClientCertificate eigenschap. Roep de GetClientCertificateAsync methode aan om dit te voorkomen. Dit is opgelost in .NET 6. Zie dit GitHub-probleem voor meer informatie. Opmerking GetClientCertificateAsync kan een null-certificaat retourneren als de client weigert er een op te geven.
Kestrel
Kestrel beheert onderhandeling van clientcertificaten met de ClientCertificateMode optie.
Voor .NET 5 of eerder Kestrel biedt geen ondersteuning voor opnieuw onderhandelen na het starten van een verbinding om een clientcertificaat te verkrijgen. Deze functie is toegevoegd in .NET 6.
Microsoft.AspNetCore.Authentication.Certificate bevat een implementatie die vergelijkbaar is met certificaatverificatie voor ASP.NET Core. Certificaatverificatie vindt plaats op TLS-niveau, lang voordat het ooit ASP.NET Core wordt. Nauwkeuriger is dit een verificatiehandler waarmee het certificaat wordt gevalideerd en u vervolgens een gebeurtenis krijgt waarin u dat certificaat kunt oplossen naar een ClaimsPrincipal.
Configureer uw server voor certificaatverificatie, of het nu IIS, KestrelAzure Web Apps of wat u ook gebruikt.
Scenario's voor proxy en load balancer
Certificaatverificatie is een stateful scenario dat voornamelijk wordt gebruikt waarbij een proxy of load balancer geen verkeer tussen clients en servers verwerkt. Als een proxy of load balancer wordt gebruikt, werkt certificaatauthenticatie alleen als de proxy of load balancer:
- Verzorgt de authenticatie.
- Geeft de gebruikersverificatiegegevens door aan de app (bijvoorbeeld in een aanvraagheader), die op de verificatiegegevens reageert.
Een alternatief voor certificaatverificatie in omgevingen waarin proxy's en load balancers worden gebruikt, is Active Directory Federated Services (ADFS) met OpenID Connect (OIDC).
Aan de slag
Verkrijg een HTTPS-certificaat, pas dit toe en configureer uw server om certificaten te vereisen.
Voeg in uw web-app een verwijzing toe naar het pakket Microsoft.AspNetCore.Authentication.Certificate . Roep vervolgens in de Startup.ConfigureServices methode services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme).AddCertificate(...); uw opties aan en geef een gemachtigde op om OnCertificateValidated eventuele aanvullende validatie uit te voeren op het clientcertificaat dat is verzonden met aanvragen. Zet deze informatie om in een ClaimsPrincipal en stel deze in op de context.Principal eigenschap.
Als de verificatie mislukt, retourneert deze handler een 403 (Forbidden) antwoord in plaats van een 401 (Unauthorized), zoals u zou verwachten. De redenering is dat de verificatie moet plaatsvinden tijdens de eerste TLS-verbinding. Tegen de tijd dat het de handler bereikt, is het te laat. U kunt de verbinding niet upgraden van een anonieme verbinding naar een verbinding met een certificaat.
Voeg ook app.UseAuthentication(); toe in de Startup.Configure methode. Anders wordt het HttpContext.User niet ingesteld op ClaimsPrincipal dat is gemaakt van het certificaat. Voorbeeld:
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(
CertificateAuthenticationDefaults.AuthenticationScheme)
.AddCertificate();
// All other service configuration
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseAuthentication();
// All other app configuration
}
In het voorgaande voorbeeld ziet u de standaardmethode voor het toevoegen van certificaatverificatie. De handler maakt een gebruikersprincipaal met behulp van de algemene certificaateigenschappen.
Certificaatvalidatie configureren
De CertificateAuthenticationOptions handler heeft een aantal ingebouwde validaties die de minimale validaties zijn die u op een certificaat moet uitvoeren. Elk van deze instellingen is standaard ingeschakeld.
AllowedCertificateTypes = Gekoppeld, Zelfondertekend, of Alle (Gekoppeld | Zelfondertekend)
Standaardwaarde: CertificateTypes.Chained
Met deze controle wordt gecontroleerd of alleen het juiste certificaattype is toegestaan. Als de app zelfondertekende certificaten gebruikt, moet deze optie worden ingesteld op CertificateTypes.All of CertificateTypes.SelfSigned.
Certificaatgebruik valideren
Standaardwaarde: true
Met deze controle wordt gecontroleerd of het certificaat dat door de client wordt gepresenteerd, het uitgebreide sleutelgebruik (EKU) voor clientverificatie heeft, of dat er helemaal geen EKU's zijn. Zoals de specificaties zeggen, als er geen EKU is opgegeven, worden alle EKU's als geldig beschouwd.
BevestigGeldigheidsperiode
Standaardwaarde: true
Met deze controle wordt gecontroleerd of het certificaat binnen de geldigheidsperiode valt. Bij elke aanvraag zorgt de handler ervoor dat een certificaat dat geldig was toen het werd gepresenteerd, niet is verlopen tijdens de huidige sessie.
Intrekkingsflag
Standaardwaarde: X509RevocationFlag.ExcludeRoot
Een vlag die aangeeft welke certificaten in de keten worden gecontroleerd op intrekking.
Intrekkingscontroles worden alleen uitgevoerd wanneer het certificaat is gekoppeld aan een basiscertificaat.
Intrekkingsmodus
Standaardwaarde: X509RevocationMode.Online
Een vlag die aangeeft hoe intrekkingscontroles worden uitgevoerd.
Het specificeren van een onlinecontrole kan leiden tot een lange vertraging terwijl er contact wordt opgenomen met de certificaatinstantie.
Intrekkingscontroles worden alleen uitgevoerd wanneer het certificaat is gekoppeld aan een basiscertificaat.
Kan ik mijn app zo configureren dat alleen een certificaat op bepaalde paden is vereist?
Dit is niet mogelijk. Onthoud dat de certificaatuitwisseling wordt uitgevoerd aan het begin van het HTTPS-gesprek. Dit wordt gedaan door de server voordat de eerste aanvraag op die verbinding wordt ontvangen, zodat het niet mogelijk is om het bereik te bepalen op basis van aanvraagvelden.
Handler-gebeurtenissen
De handler heeft twee gebeurtenissen:
-
OnAuthenticationFailed: Wordt aangeroepen als er een uitzondering optreedt tijdens de verificatie en kunt u reageren. -
OnCertificateValidated: Aangeroepen nadat het certificaat succesvol gevalideerd is en er een standaardprincipal is gemaakt. Met deze gebeurtenis kunt u uw eigen validatie uitvoeren en de principal uitbreiden of vervangen. Voorbeelden hiervan zijn:Bepalen of het certificaat bekend is bij uw services.
Uw eigen principal samenstellen. Bekijk het volgende voorbeeld in
Startup.ConfigureServices:services.AddAuthentication( CertificateAuthenticationDefaults.AuthenticationScheme) .AddCertificate(options => { options.Events = new CertificateAuthenticationEvents { OnCertificateValidated = context => { var claims = new[] { new Claim( ClaimTypes.NameIdentifier, context.ClientCertificate.Subject, ClaimValueTypes.String, context.Options.ClaimsIssuer), new Claim(ClaimTypes.Name, context.ClientCertificate.Subject, ClaimValueTypes.String, context.Options.ClaimsIssuer) }; context.Principal = new ClaimsPrincipal( new ClaimsIdentity(claims, context.Scheme.Name)); context.Success(); return Task.CompletedTask; } }; });
Als het binnenkomende certificaat niet voldoet aan uw extra validatie, geef dan een foutreden door aan context.Fail("failure reason").
Voor echte functionaliteit wilt u waarschijnlijk een service aanroepen die is geregistreerd bij afhankelijkheidsinjectie die verbinding maakt met een database of een ander type gebruikersarchief. Open uw service met behulp van de context die is doorgegeven aan uw gemachtigde. Bekijk het volgende voorbeeld in Startup.ConfigureServices:
services.AddAuthentication(
CertificateAuthenticationDefaults.AuthenticationScheme)
.AddCertificate(options =>
{
options.Events = new CertificateAuthenticationEvents
{
OnCertificateValidated = context =>
{
var validationService =
context.HttpContext.RequestServices
.GetRequiredService<ICertificateValidationService>();
if (validationService.ValidateCertificate(
context.ClientCertificate))
{
var claims = new[]
{
new Claim(
ClaimTypes.NameIdentifier,
context.ClientCertificate.Subject,
ClaimValueTypes.String,
context.Options.ClaimsIssuer),
new Claim(
ClaimTypes.Name,
context.ClientCertificate.Subject,
ClaimValueTypes.String,
context.Options.ClaimsIssuer)
};
context.Principal = new ClaimsPrincipal(
new ClaimsIdentity(claims, context.Scheme.Name));
context.Success();
}
return Task.CompletedTask;
}
};
});
Conceptueel is de validatie van het certificaat een autorisatieprobleem. Het toevoegen van een controle op bijvoorbeeld een uitgever of vingerafdruk in een autorisatiebeleid, in plaats van binnen OnCertificateValidated, is volledig acceptabel.
Configureer uw server zo dat certificaten vereist zijn.
Kestrel
Program.cs Configureer Kestrelals volgt in:
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args)
{
return Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
webBuilder.ConfigureKestrel(o =>
{
o.ConfigureHttpsDefaults(o =>
o.ClientCertificateMode = ClientCertificateMode.RequireCertificate);
});
});
}
Opmerking
Eindpunten die zijn gemaakt door Listenaan te roepen voordatConfigureHttpsDefaults worden aangeroepen, worden de standaardwaarden niet toegepast.
IIS
Voer de volgende stappen uit in IIS Manager:
- Selecteer uw site op het tabblad Verbindingen .
- Dubbelklik op de optie SSL-instellingen in het venster Functiesweergave .
- Vink het selectievakje SSL vereisen aan en selecteer de optie Vereisen in de sectie Clientcertificaten.
Azure en aangepaste webproxy's
Raadpleeg de host- en implementatiedocumentatie voor het configureren van de middleware voor het doorsturen van certificaten.
Certificaatverificatie gebruiken in Azure Web Apps
Er is geen doorstuurconfiguratie vereist voor Azure. De doorstuurconfiguratie wordt ingesteld door de Middleware voor het doorsturen van certificaten.
Opmerking
Middleware voor het doorsturen van certificaten is vereist voor dit scenario.
Zie Een TLS/SSL-certificaat gebruiken in uw code in Azure App Service (Documentatie voor Azure) voor meer informatie.
Certificaatverificatie gebruiken in aangepaste webproxy's
De AddCertificateForwarding methode wordt gebruikt om het volgende op te geven:
- De naam van de clientheader.
- Hoe het certificaat moet worden geladen (met behulp van de
HeaderConvertereigenschap).
In aangepaste webproxy's wordt het certificaat doorgegeven als een aangepaste aanvraagheader, bijvoorbeeld X-SSL-CERT. Als u het wilt gebruiken, configureert u het doorsturen van certificaten in Startup.ConfigureServices:
public void ConfigureServices(IServiceCollection services)
{
services.AddCertificateForwarding(options =>
{
options.CertificateHeader = "X-SSL-CERT";
options.HeaderConverter = (headerValue) =>
{
X509Certificate2 clientCertificate = null;
if(!string.IsNullOrWhiteSpace(headerValue))
{
byte[] bytes = StringToByteArray(headerValue);
clientCertificate = new X509Certificate2(bytes);
}
return clientCertificate;
};
});
}
private static byte[] StringToByteArray(string hex)
{
int NumberChars = hex.Length;
byte[] bytes = new byte[NumberChars / 2];
for (int i = 0; i < NumberChars; i += 2)
{
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
}
return bytes;
}
nl-NL: Als de app omgekeerd geproxy'd wordt door NGINX met de configuratie proxy_set_header ssl-client-cert $ssl_client_escaped_cert of geïmplementeerd op Kubernetes met behulp van NGINX Ingress, wordt het clientcertificaat doorgegeven aan de app in URL-gecodeerde vorm. Als u het certificaat wilt gebruiken, decodert u het als volgt:
Voeg de naamruimte voor System.Net toe aan het begin van Startup.cs:
using System.Net;
In Startup.ConfigureServices:
services.AddCertificateForwarding(options =>
{
options.CertificateHeader = "ssl-client-cert";
options.HeaderConverter = (headerValue) =>
{
X509Certificate2 clientCertificate = null;
if (!string.IsNullOrWhiteSpace(headerValue))
{
var bytes = UrlEncodedPemToByteArray(headerValue);
clientCertificate = new X509Certificate2(bytes);
}
return clientCertificate;
};
});
Voeg de UrlEncodedPemToByteArray methode toe:
private static byte[] UrlEncodedPemToByteArray(string urlEncodedBase64Pem)
{
var base64Pem = WebUtility.UrlDecode(urlEncodedBase64Pem);
var base64Cert = base64Pem
.Replace("-----BEGIN CERTIFICATE-----", string.Empty)
.Replace("-----END CERTIFICATE-----", string.Empty)
.Trim();
return Convert.FromBase64String(base64Cert);
}
De Startup.Configure methode voegt vervolgens de middleware toe.
UseCertificateForwarding wordt aangeroepen vóór de aanroepen naar UseAuthentication en UseAuthorization:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
app.UseRouting();
app.UseCertificateForwarding();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
Een afzonderlijke klasse kan worden gebruikt om validatielogica te implementeren. Omdat hetzelfde zelfondertekende certificaat in dit voorbeeld wordt gebruikt, moet u ervoor zorgen dat alleen uw certificaat kan worden gebruikt. Controleer of de vingerafdrukken van zowel het clientcertificaat als het servercertificaat overeenkomen, anders kan elk certificaat worden gebruikt en is voldoende om te verifiëren. Dit wordt gebruikt in de AddCertificate methode. U kunt hier ook het onderwerp of de uitgever valideren als u intermediaire of subcertificaten gebruikt.
using System.IO;
using System.Security.Cryptography.X509Certificates;
namespace AspNetCoreCertificateAuthApi
{
public class MyCertificateValidationService
{
public bool ValidateCertificate(X509Certificate2 clientCertificate)
{
// Do not hardcode passwords in production code
// Use thumbprint or key vault
var cert = new X509Certificate2(
Path.Combine("sts_dev_cert.pfx"), "1234");
if (clientCertificate.Thumbprint == cert.Thumbprint)
{
return true;
}
return false;
}
}
}
Een HttpClient implementeren met behulp van een certificaat en de HttpClientHandler
De HttpClientHandler kan rechtstreeks in de constructor van de HttpClient klasse worden toegevoegd. Er moet voorzichtig te werk worden gegaan bij het maken van exemplaren van de HttpClient. Het HttpClient certificaat wordt vervolgens met elke aanvraag verzonden.
private async Task<JsonDocument> GetApiDataUsingHttpClientHandler()
{
var cert = new X509Certificate2(Path.Combine(_environment.ContentRootPath, "sts_dev_cert.pfx"), "1234");
var handler = new HttpClientHandler();
handler.ClientCertificates.Add(cert);
var client = new HttpClient(handler);
var request = new HttpRequestMessage()
{
RequestUri = new Uri("https://localhost:44379/api/values"),
Method = HttpMethod.Get,
};
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
var responseContent = await response.Content.ReadAsStringAsync();
var data = JsonDocument.Parse(responseContent);
return data;
}
throw new ApplicationException($"Status code: {response.StatusCode}, Error: {response.ReasonPhrase}");
}
Een HttpClient implementeren met behulp van een certificaat en een httpclient met de naam IHttpClientFactory
In het volgende voorbeeld wordt een clientcertificaat aan een HttpClientHandler toegevoegd met behulp van de ClientCertificates eigenschap van de handler. Deze handler kan vervolgens worden gebruikt in een benoemd exemplaar van een HttpClient met behulp van de ConfigurePrimaryHttpMessageHandler methode. Dit is ingesteld in Startup.ConfigureServices:
var clientCertificate =
new X509Certificate2(
Path.Combine(_environment.ContentRootPath, "sts_dev_cert.pfx"), "1234");
services.AddHttpClient("namedClient", c =>
{
}).ConfigurePrimaryHttpMessageHandler(() =>
{
var handler = new HttpClientHandler();
handler.ClientCertificates.Add(clientCertificate);
return handler;
});
De IHttpClientFactory kan vervolgens worden gebruikt om het benoemde exemplaar op te halen met behulp van de handler en het certificaat. De CreateClient methode met de naam van de client die in de Startup klasse is gedefinieerd, wordt gebruikt om het exemplaar op te halen. De HTTP-aanvraag kan naar behoefte worden verzonden met behulp van de client.
private readonly IHttpClientFactory _clientFactory;
public ApiService(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
private async Task<JsonDocument> GetApiDataWithNamedClient()
{
var client = _clientFactory.CreateClient("namedClient");
var request = new HttpRequestMessage()
{
RequestUri = new Uri("https://localhost:44379/api/values"),
Method = HttpMethod.Get,
};
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
var responseContent = await response.Content.ReadAsStringAsync();
var data = JsonDocument.Parse(responseContent);
return data;
}
throw new ApplicationException($"Status code: {response.StatusCode}, Error: {response.ReasonPhrase}");
}
Als het juiste certificaat naar de server wordt verzonden, worden de gegevens geretourneerd. Als er geen certificaat of het verkeerde certificaat wordt verzonden, wordt een HTTP 403-statuscode geretourneerd.
Certificaten maken in PowerShell
Het maken van de certificaten is het moeilijkste onderdeel van het instellen van deze stroom. U kunt een basiscertificaat maken met behulp van de New-SelfSignedCertificate PowerShell-cmdlet. Wanneer u het certificaat maakt, gebruikt u een sterk wachtwoord. Het is belangrijk om de KeyUsageProperty parameter en de KeyUsage parameter toe te voegen, zoals wordt weergegeven.
Basis-CA maken
New-SelfSignedCertificate -DnsName "root_ca_dev_damienbod.com", "root_ca_dev_damienbod.com" -CertStoreLocation "cert:\LocalMachine\My" -NotAfter (Get-Date).AddYears(20) -FriendlyName "root_ca_dev_damienbod.com" -KeyUsageProperty All -KeyUsage CertSign, CRLSign, DigitalSignature
$mypwd = ConvertTo-SecureString -String "1234" -Force -AsPlainText
Get-ChildItem -Path cert:\localMachine\my\"The thumbprint..." | Export-PfxCertificate -FilePath C:\git\root_ca_dev_damienbod.pfx -Password $mypwd
Export-Certificate -Cert cert:\localMachine\my\"The thumbprint..." -FilePath root_ca_dev_damienbod.crt
Opmerking
De -DnsName parameterwaarde moet overeenkomen met het implementatiedoel van de app. Bijvoorbeeld 'localhost' voor ontwikkeling.
Installeren in de vertrouwde basis
Het rootcertificaat moet op uw hostsysteem vertrouwd worden. Een basiscertificaat dat niet is gemaakt door een certificeringsinstantie, wordt niet standaard vertrouwd. Zie deze vraag voor informatie over het vertrouwen van het basiscertificaat in Windows.
Tussenliggend certificaat
Er kan nu een tussenliggend certificaat worden gemaakt op basis van het basiscertificaat. Dit is niet vereist voor alle use cases, maar mogelijk moet u veel certificaten maken of groepen certificaten activeren of uitschakelen. De TextExtension parameter is vereist om de padlengte in te stellen in de basisbeperkingen van het certificaat.
Het tussenliggende certificaat kan vervolgens worden toegevoegd aan het vertrouwde tussenliggende certificaat in het Windows-hostsysteem.
$mypwd = ConvertTo-SecureString -String "1234" -Force -AsPlainText
$parentcert = ( Get-ChildItem -Path cert:\LocalMachine\My\"The thumbprint of the root..." )
New-SelfSignedCertificate -certstorelocation cert:\localmachine\my -dnsname "intermediate_dev_damienbod.com" -Signer $parentcert -NotAfter (Get-Date).AddYears(20) -FriendlyName "intermediate_dev_damienbod.com" -KeyUsageProperty All -KeyUsage CertSign, CRLSign, DigitalSignature -TextExtension @("2.5.29.19={text}CA=1&pathlength=1")
Get-ChildItem -Path cert:\localMachine\my\"The thumbprint..." | Export-PfxCertificate -FilePath C:\git\AspNetCoreCertificateAuth\Certs\intermediate_dev_damienbod.pfx -Password $mypwd
Export-Certificate -Cert cert:\localMachine\my\"The thumbprint..." -FilePath intermediate_dev_damienbod.crt
Een onderliggend certificaat maken op basis van een tussenliggend certificaat
Er kan een kindercertificaat worden gemaakt op basis van het tussenliggende certificaat. Dit is de eindentiteit die geen kindcertificaten hoeft te maken.
$parentcert = ( Get-ChildItem -Path cert:\LocalMachine\My\"The thumbprint from the Intermediate certificate..." )
New-SelfSignedCertificate -certstorelocation cert:\localmachine\my -dnsname "child_a_dev_damienbod.com" -Signer $parentcert -NotAfter (Get-Date).AddYears(20) -FriendlyName "child_a_dev_damienbod.com"
$mypwd = ConvertTo-SecureString -String "1234" -Force -AsPlainText
Get-ChildItem -Path cert:\localMachine\my\"The thumbprint..." | Export-PfxCertificate -FilePath C:\git\AspNetCoreCertificateAuth\Certs\child_a_dev_damienbod.pfx -Password $mypwd
Export-Certificate -Cert cert:\localMachine\my\"The thumbprint..." -FilePath child_a_dev_damienbod.crt
Kindcertificaat maken van rootcertificaat
Een kindcertificaat kan ook rechtstreeks vanuit het basiscertificaat worden gemaakt.
$rootcert = ( Get-ChildItem -Path cert:\LocalMachine\My\"The thumbprint from the root cert..." )
New-SelfSignedCertificate -certstorelocation cert:\localmachine\my -dnsname "child_a_dev_damienbod.com" -Signer $rootcert -NotAfter (Get-Date).AddYears(20) -FriendlyName "child_a_dev_damienbod.com"
$mypwd = ConvertTo-SecureString -String "1234" -Force -AsPlainText
Get-ChildItem -Path cert:\localMachine\my\"The thumbprint..." | Export-PfxCertificate -FilePath C:\git\AspNetCoreCertificateAuth\Certs\child_a_dev_damienbod.pfx -Password $mypwd
Export-Certificate -Cert cert:\localMachine\my\"The thumbprint..." -FilePath child_a_dev_damienbod.crt
Voorbeeld rootcertificaat - tussenliggend certificaat - certificaat
$mypwdroot = ConvertTo-SecureString -String "1234" -Force -AsPlainText
$mypwd = ConvertTo-SecureString -String "1234" -Force -AsPlainText
New-SelfSignedCertificate -DnsName "root_ca_dev_damienbod.com", "root_ca_dev_damienbod.com" -CertStoreLocation "cert:\LocalMachine\My" -NotAfter (Get-Date).AddYears(20) -FriendlyName "root_ca_dev_damienbod.com" -KeyUsageProperty All -KeyUsage CertSign, CRLSign, DigitalSignature
Get-ChildItem -Path cert:\localMachine\my\0C89639E4E2998A93E423F919B36D4009A0F9991 | Export-PfxCertificate -FilePath C:\git\root_ca_dev_damienbod.pfx -Password $mypwdroot
Export-Certificate -Cert cert:\localMachine\my\0C89639E4E2998A93E423F919B36D4009A0F9991 -FilePath root_ca_dev_damienbod.crt
$rootcert = ( Get-ChildItem -Path cert:\LocalMachine\My\0C89639E4E2998A93E423F919B36D4009A0F9991 )
New-SelfSignedCertificate -certstorelocation cert:\localmachine\my -dnsname "child_a_dev_damienbod.com" -Signer $rootcert -NotAfter (Get-Date).AddYears(20) -FriendlyName "child_a_dev_damienbod.com" -KeyUsageProperty All -KeyUsage CertSign, CRLSign, DigitalSignature -TextExtension @("2.5.29.19={text}CA=1&pathlength=1")
Get-ChildItem -Path cert:\localMachine\my\BA9BF91ED35538A01375EFC212A2F46104B33A44 | Export-PfxCertificate -FilePath C:\git\AspNetCoreCertificateAuth\Certs\child_a_dev_damienbod.pfx -Password $mypwd
Export-Certificate -Cert cert:\localMachine\my\BA9BF91ED35538A01375EFC212A2F46104B33A44 -FilePath child_a_dev_damienbod.crt
$parentcert = ( Get-ChildItem -Path cert:\LocalMachine\My\BA9BF91ED35538A01375EFC212A2F46104B33A44 )
New-SelfSignedCertificate -certstorelocation cert:\localmachine\my -dnsname "child_b_from_a_dev_damienbod.com" -Signer $parentcert -NotAfter (Get-Date).AddYears(20) -FriendlyName "child_b_from_a_dev_damienbod.com"
Get-ChildItem -Path cert:\localMachine\my\141594A0AE38CBBECED7AF680F7945CD51D8F28A | Export-PfxCertificate -FilePath C:\git\AspNetCoreCertificateAuth\Certs\child_b_from_a_dev_damienbod.pfx -Password $mypwd
Export-Certificate -Cert cert:\localMachine\my\141594A0AE38CBBECED7AF680F7945CD51D8F28A -FilePath child_b_from_a_dev_damienbod.crt
Wanneer u de basis-, tussen- of onderliggende certificaten gebruikt, kunnen de certificaten naar behoefte worden gevalideerd met behulp van de vingerafdruk of PublicKey.
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography.X509Certificates;
namespace AspNetCoreCertificateAuthApi
{
public class MyCertificateValidationService
{
public bool ValidateCertificate(X509Certificate2 clientCertificate)
{
return CheckIfThumbprintIsValid(clientCertificate);
}
private bool CheckIfThumbprintIsValid(X509Certificate2 clientCertificate)
{
var listOfValidThumbprints = new List<string>
{
"141594A0AE38CBBECED7AF680F7945CD51D8F28A",
"0C89639E4E2998A93E423F919B36D4009A0F9991",
"BA9BF91ED35538A01375EFC212A2F46104B33A44"
};
if (listOfValidThumbprints.Contains(clientCertificate.Thumbprint))
{
return true;
}
return false;
}
}
}
Optionele clientcertificaten
Deze sectie bevat informatie voor apps die een subset van de app met een certificaat moeten beveiligen. Voor een Razor pagina of controller in de app zijn bijvoorbeeld clientcertificaten vereist. Dit brengt uitdagingen met zich mee als clientcertificaten:
- Zijn een TLS-functie, geen HTTP-functie.
- Wordt onderhandeld per verbinding en meestal aan het begin van de verbinding voordat er HTTP-gegevens beschikbaar zijn.
Er zijn twee benaderingen voor het implementeren van optionele clientcertificaten:
- Gebruik afzonderlijke hostnamen (SNI) en doorsturen. Hoewel er meer werk nodig is om te configureren, wordt dit aanbevolen omdat dit werkt in de meeste omgevingen en protocollen.
- Heronderhandeling tijdens een HTTP-aanvraag. Dit heeft verschillende beperkingen en wordt niet aanbevolen.
Afzonderlijke hosts (SNI)
Aan het begin van de verbinding is alleen de SNI-† (Server Name Indication) bekend. Clientcertificaten kunnen per hostnaam worden geconfigureerd, zodat de ene host deze vereist en een andere niet.
- Binding instellen voor het domein en subdomein:
- Stel bijvoorbeeld bindingen in op
contoso.comenmyClient.contoso.com. Voor decontoso.comhost is geen clientcertificaat vereist, maarmyClient.contoso.comwel. - Zie voor meer informatie:
-
Kestrel webserver in ASP.NET Core:
- ListenOptions.UseHttps
- ClientCertificateMode
- Opmerking Kestrel biedt momenteel geen ondersteuning voor meerdere TLS-configuraties voor één binding. U hebt twee bindingen met unieke IP-adressen of poorten nodig. Zie dit GitHub-probleem voor meer informatie.
- IIS
- HTTP.sys: Windows Server configureren
-
Kestrel webserver in ASP.NET Core:
- Stel bijvoorbeeld bindingen in op
.NET 5 of hoger voegt handigere ondersteuning toe voor het omleiden om optionele clientcertificaten te verkrijgen. Zie het voorbeeld van optionele certificaten voor meer informatie.
- Voor aanvragen voor de web-app waarvoor een clientcertificaat vereist is maar niet aanwezig is:
- Omleiden naar dezelfde pagina met behulp van het met het clientcertificaat beveiligde subdomein.
- Bijvoorbeeld omleiden naar
myClient.contoso.com/requestedPage. Omdat de aanvraag naarmyClient.contoso.com/requestedPageeen andere hostnaam heeft dancontoso.com/requestedPage, brengt de client een andere verbinding tot stand en wordt het clientcertificaat verstrekt. - Zie Inleiding tot autorisatie in ASP.NET Core voor meer informatie.
† Server Name Indication (SNI) is een TLS-extensie om een virtueel domein op te nemen als onderdeel van SSL-onderhandeling. Dit betekent dat de virtuele domeinnaam of een hostnaam effectief kan worden gebruikt om het netwerkeindpunt te identificeren.
Heronderhandeling
TLS-heronderhandeling is een proces waarmee de client en server de versleutelingsvereisten voor een afzonderlijke verbinding opnieuw kunnen beoordelen, inclusief het aanvragen van een clientcertificaat als dat nog niet eerder is opgegeven. TLS-heronderhandeling is een beveiligingsrisico en wordt niet aanbevolen omdat:
- In HTTP/1.1 moet de server eerst HTTP-gegevens bufferen of verwerken die in de doorgang zijn, zoals POST-verzoeklichamen om ervoor te zorgen dat de verbinding vrij is voor de heronderhandeling. Anders kan de heronderhandeling stoppen met reageren of mislukken.
- HTTP/2 en HTTP/3 verbieden expliciet heronderhandeling.
- Er zijn beveiligingsrisico's verbonden aan heronderhandeling. TLS 1.3 heeft de heronderhandeling van de hele verbinding verwijderd en vervangen door een nieuwe extensie voor alleen het aanvragen van een clientcertificaat nadat de verbinding is gestart. Dit mechanisme wordt weergegeven via dezelfde API's en is nog steeds onderhevig aan de eerdere beperkingen van buffering en HTTP-protocolversies.
De implementatie en configuratie van deze functie variëren per server- en frameworkversie.
IIS
IIS beheert namens u de onderhandeling van het clientcertificaat. Een subsectie van de toepassing kan de SslRequireCert optie inschakelen om te onderhandelen over het clientcertificaat voor deze aanvragen. Zie Configuratie in de IIS-documentatie voor meer informatie.
IIS buffert automatisch eventuele aanvraagbodygegevens tot een geconfigureerde groottelimiet voordat opnieuw wordt onderhandeld. Aanvragen die de limiet overschrijden, worden geweigerd met een 413-antwoord. Deze limiet is standaard ingesteld op 48 kB en kan worden geconfigureerd door de uploadReadAheadSize in te stellen.
HttpSys
HttpSys heeft twee instellingen die de onderhandeling van het clientcertificaat regelen en beide moeten worden ingesteld. De eerste bevindt zich in netsh.exe onder http add sslcert clientcertnegotiation=enable/disable. Deze vlag geeft aan of het clientcertificaat moet worden onderhandeld aan het begin van een verbinding en moet worden ingesteld disable op voor optionele clientcertificaten. Zie de netsh-documenten voor meer informatie.
De andere instelling is ClientCertificateMethod. Wanneer ingesteld op AllowRenegotation, kan het clientcertificaat tijdens een aanvraag opnieuw worden onderhandeld.
NOTITIE De toepassing moet de hoofdtekstgegevens van de aanvraag bufferen of gebruiken voordat de heronderhandeling wordt uitgevoerd, anders reageert de aanvraag mogelijk niet meer.
Er is een bekend probleem waarbij het inschakelen AllowRenegotation ervoor kan zorgen dat de heronderhandeling synchroon plaatsvindt bij het openen van de ClientCertificate eigenschap. Roep de GetClientCertificateAsync methode aan om dit te voorkomen. Dit is opgelost in .NET 6. Zie dit GitHub-probleem voor meer informatie. Opmerking GetClientCertificateAsync kan een null-certificaat retourneren als de client weigert er een op te geven.
Kestrel
Kestrel beheert onderhandeling van clientcertificaten met de ClientCertificateMode optie.
Voor .NET 5 of eerder Kestrel biedt geen ondersteuning voor opnieuw onderhandelen na het starten van een verbinding om een clientcertificaat te verkrijgen. Deze functie is toegevoegd in .NET 6.
Laat vragen, opmerkingen en andere feedback over optionele clientcertificaten in de discussiethread achter voor GitHub probleem #18720.