Konfigurace ověřování certifikátů v ASP.NET Core
Microsoft.AspNetCore.Authentication.Certificateobsahuje implementaci podobnou ověřování certifikátů pro ASP.NET Core. Ověřování certifikátů probíhá na úrovni protokolu TLS, dlouho předtím, než se ASP.NET Core. Přesněji jde o obslužnou rutinu ověřování, která ověří certifikát a pak vám poskytne událost, kde můžete tento certifikát přeložit na ClaimsPrincipal .
Nakonfigurujte server pro ověřování certifikátů, ať už je to služba IIS, , Azure Web Apps nebo cokoli Kestrel jiného, co používáte.
Scénáře proxy serveru a nástroje pro vyrovnávání zatížení
Ověřování certifikátů je stavový scénář, který se primárně používá v případě, že proxy server nebo nástroj pro vyrovnávání zatížení nezvládá provoz mezi klienty a servery. Pokud se používá proxy server nebo nástroj pro vyrovnávání zatížení, ověřování certifikátů funguje jenom v případě, že proxy server nebo nástroj pro vyrovnávání zatížení:
- Zpracovává ověřování.
- Předá aplikaci ověřovací informace uživatele (například v hlavičce požadavku), která funguje s ověřovacími informacemi.
Alternativou k ověřování certifikátů v prostředích, kde se používají proxy a nástroje pro vyrovnávání zatížení, je služba Active Directory Federated Services (ADFS) s OpenID Připojení (OIDC).
Začínáme
Získejte certifikát HTTPS, použijte ho a nakonfigurujte server tak, aby vyžadoval certifikáty.
Ve webové aplikaci přidejte odkaz na balíček Microsoft.AspNetCore.Authentication.Certificate. Potom v metodě zavolejte s vašimi možnostmi a popište delegátovi, aby u klientského certifikátu odeslaného s požadavky provést jakékoli dodatečné Startup.ConfigureServices services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme).AddCertificate(...); OnCertificateValidated ověření. Změnit tyto informace na a ClaimsPrincipal nastavit je u vlastnosti context.Principal .
Pokud se ověření nezdaří, tato obslužná rutina 403 (Forbidden) vrátí odpověď místo , jak můžete 401 (Unauthorized) očekávat. Důvodem je, že ověřování by mělo pro dojít během počátečního připojení TLS. Než obslužná rutina dosáhne, je příliš pozdě. Neexistuje žádný způsob, jak upgradovat připojení z anonymního připojení na připojení s certifikátem.
Přidejte app.UseAuthentication(); také Startup.Configure metodu . V opačném případě se z certifikátu HttpContext.User ClaimsPrincipal nenastaví na hodnotu vytvořenou. Například:
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
}
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
}
Předchozí příklad ukazuje výchozí způsob, jak přidat ověřování certifikátem. Obslužná rutina vytvoří objekt zabezpečení uživatele pomocí společných vlastností certifikátu.
Konfigurace ověření certifikátu
Obslužná CertificateAuthenticationOptions rutina obsahuje některá předdefinová ověření, která jsou minimálními ověřeními, která byste měli s certifikátem provést. Každé z těchto nastavení je ve výchozím nastavení povolené.
AllowedCertificateTypes = Chained, SelfSigned nebo All (zřetězované | SelfSigned)
Výchozí hodnota: CertificateTypes.Chained
Tato kontrola ověří, že je povolený jenom příslušný typ certifikátu. Pokud aplikace používá certifikáty podepsané svým držitelem, musí být tato možnost nastavená na CertificateTypes.All nebo CertificateTypes.SelfSigned .
ValidateCertificateUse
Výchozí hodnota: true
Tato kontrola ověří, zda má certifikát prezentovaný klientem rozšířené použití klíče ověření klienta (EKU) nebo žádné rozšířené klíče EKU. Jak je uvedeno v specifikacích, pokud není zadán žádný EKU, pak se všechny EKU považují za platné.
ValidateValidityPeriod
Výchozí hodnota: true
Tato kontrola ověří, že certifikát je v rámci doby platnosti. U každého požadavku obslužná rutina zajišťuje, že certifikát, který byl platný, když byl prezentován, nevyšel během aktuální relace.
Prodleva odvolání
Výchozí hodnota: X509RevocationFlag.ExcludeRoot
Příznak, který určuje, u kterých certifikátů v řetězu se kontroluje odvolání.
Kontroly odvolání se provádějí pouze v případě, že je certifikát zřetěován s kořenovým certifikátem.
Režim odvolání
Výchozí hodnota: X509RevocationMode.Online
Příznak, který určuje, jak se provádějí kontroly odvolání.
Zadání online kontroly může způsobit dlouhé zpoždění při kontaktování certifikační autority.
Kontroly odvolání se provádějí pouze v případě, že je certifikát zřetěován s kořenovým certifikátem.
Můžu aplikaci nakonfigurovat tak, aby vyžadovala certifikát jenom na určitých cestách?
To není možné. Mějte na paměti, že výměna certifikátů se provádí na začátku konverzace HTTPS. Server ji provádí před přijetím prvního požadavku na toto připojení, takže není možné vymezený rozsah na základě žádných polí požadavku.
Události obslužné rutiny
Obslužná rutina má dvě události:
OnAuthenticationFailed: Volá se, pokud během ověřování dojde k výjimce a umožní vám reagovat.OnCertificateValidated: Volá se po ověření certifikátu, úspěšně se ověří a vytvoří se výchozí objekt zabezpečení. Tato událost vám umožní provést vlastní ověření a rozšířit nebo nahradit objekt zabezpečení. Příklady:Určení, jestli je certifikát pro vaše služby známý
Vytvoření vlastního objektu zabezpečení. Zvažte následující příklad v
Startup.ConfigureServicessouboru :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; } }; });
Pokud zjistíte, že příchozí certifikát nesplňuje vaše dodatečné ověření, zavolejte context.Fail("failure reason") z důvodu selhání.
Pro skutečné funkce budete pravděpodobně chtít volat službu zaregistrovanou v injektáži závislostí, která se připojuje k databázi nebo jinému typu uživatelského úložiště. Přístup ke službě pomocí kontextu předaly do delegáta. Zvažte následující příklad v Startup.ConfigureServices souboru :
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;
}
};
});
Koncepčně se ověření certifikátu týká autorizace. Přidání kontroly, například vystavitele nebo kryptografického otisku v zásadách autorizace, a ne uvnitř OnCertificateValidated , je naprosto přijatelné.
Konfigurace serveru tak, aby vyžadoval certifikáty
Kestrel
V souboru Program.cs Kestrel nakonfigurujte následujícím způsobem:
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);
});
});
}
Poznámka
U koncových bodů Listen vytvořených voláním ConfigureHttpsDefaults před voláním se nebudou uplatňovat výchozí hodnoty.
IIS
Ve Správci služby IIS proveďte následující kroky:
- Na kartě Připojení vyberte svůj web.
- V okně Zobrazení funkcí poklikejte Nastavení ssl.
- Zaškrtněte políčko Vyžadovat SSL a v části Klientské certifikáty vyberte přepínač Vyžadovat.

Azure a vlastní webové servery prox
Informace o konfiguraci middlewaru pro předávání certifikátů najdete v dokumentaci k hostiteli a nasazení.
Použití ověřování certifikátů v Azure Web Apps
Azure nevyžaduje konfiguraci předávání dál. Konfiguraci předávání nastaví middleware pro předávání certifikátů.
Poznámka
Pro tento scénář se vyžaduje middleware pro předávání certifikátů.
Další informace najdete v tématu Použití certifikátu TLS/SSL v kódu v Azure App Service (dokumentace Azure).
Použití ověřování certifikátů ve vlastních webových serverech pro
Metoda AddCertificateForwarding se používá k určení:
- Název hlavičky klienta.
- Způsob načtení certifikátu (pomocí
HeaderConvertervlastnosti ).
Ve vlastních webových serverech prox se certifikát předává jako vlastní hlavička požadavku, například X-SSL-CERT . Pokud ho chcete použít, nakonfigurujte předávání certifikátů v nástroji 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;
}
Pokud je aplikace reverzním serverem proxied serverem NGINX s konfigurací nebo nasazená v Kubernetes pomocí příchozího přenosu dat NGINX, klientský certifikát se předá aplikaci ve formátu zakódované v adrese proxy_set_header ssl-client-cert $ssl_client_escaped_cert URL. Pokud chcete certifikát použít, dekódovat ho následujícím způsobem:
V Startup.ConfigureServices souboru ( 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;
};
});
Na začátek souboru System.Net přidejte obor názvů pro Startup.cs :
using System.Net;
V 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;
};
});
Přidejte UrlEncodedPemToByteArray metodu :
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);
}
Metoda Startup.Configure pak přidá middleware. UseCertificateForwarding se volá před voláním a UseAuthentication UseAuthorization :
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
app.UseRouting();
app.UseCertificateForwarding();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
K implementaci logiky ověřování lze použít samostatnou třídu. Vzhledem k tomu, že se v tomto příkladu používá stejný certifikát podepsaný svým držitelem, ujistěte se, že je možné použít pouze váš certifikát. Ověřte, že se kryptografický otisk klientského certifikátu i certifikátu serveru shoduje, jinak je možné použít libovolný certifikát a bude stačit k ověření. To by se použilo uvnitř AddCertificate metody . Pokud používáte zprostředkující nebo podřízené certifikáty, můžete tady také ověřit předmět nebo vystavitele.
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;
}
}
}
Implementace HttpClient pomocí certifikátu a HttpClientHandler
Objekt HttpClientHandler může být přidán přímo do konstruktoru třídy HttpClient . Při vytváření instancí objektu je třeba HttpClient opatrnost. HttpClientPříkaz pak odešle certifikát s každou žádostí.
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}");
}
Implementace HttpClient pomocí certifikátu a s názvem HttpClient z IHttpClientFactory
V následujícím příkladu je klientský certifikát přidán do HttpClientHandler objektu pomocí vlastnosti z obslužné ClientCertificates rutiny. Tuto obslužnou rutinu lze poté použít v pojmenované instanci HttpClient pomocí ConfigurePrimaryHttpMessageHandler metody . Toto je nastavení v souboru Startup.ConfigureServices :
var clientCertificate =
new X509Certificate2(
Path.Combine(_environment.ContentRootPath, "sts_dev_cert.pfx"), "1234");
var handler = new HttpClientHandler();
handler.ClientCertificates.Add(clientCertificate);
services.AddHttpClient("namedClient", c =>
{
}).ConfigurePrimaryHttpMessageHandler(() => handler);
Lze IHttpClientFactory pak použít k získání pojmenované instance s obslužnou rutinou a certifikátem. Metoda s názvem klienta definovaným ve třídě se používá CreateClient k získání Startup instance. Požadavek HTTP je možné odeslat pomocí klienta podle potřeby.
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}");
}
Pokud se na server odesílá správný certifikát, vrátí se data. Pokud není odeslán žádný certifikát nebo nesprávný certifikát, vrátí se stavový kód HTTP 403.
Vytváření certifikátů v PowerShellu
Vytvoření certifikátů je při nastavování tohoto toku nejsnáz. Kořenový certifikát je možné vytvořit pomocí rutiny New-SelfSignedCertificate PowerShellu. Při vytváření certifikátu použijte silné heslo. Je důležité přidat parametr KeyUsageProperty a parametr , jak je KeyUsage znázorněno níže.
Vytvoření kořenové certifikační autority
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
Poznámka
Hodnota -DnsName parametru musí odpovídat cíli nasazení aplikace. Například "localhost" pro vývoj.
Instalace v důvěryhodném kořenovém adresáři
Kořenový certifikát musí být ve vašem hostitelském systému důvěryhodný. Kořenový certifikát, který nebyl vytvořen certifikační autoritou, nebude ve výchozím nastavení důvěryhodný. Následující odkaz vysvětluje, jak toho lze dosáhnout v Windows:
Zprostředkující certifikát
Zprostředkující certifikát je teď možné vytvořit z kořenového certifikátu. To není nutné pro všechny případy použití, ale možná budete muset vytvořit mnoho certifikátů nebo budete muset aktivovat nebo zakázat skupiny certifikátů. Parametr TextExtension je nutný k nastavení délky cesty v základních omezeních certifikátu.
Zprostředkující certifikát je pak možné přidat do důvěryhodného zprostředkujícího certifikátu v Windows systému.
$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
Vytvoření podřízeného certifikátu z zprostředkujícího certifikátu
Podřízený certifikát lze vytvořit z zprostředkujícího certifikátu. Toto je koncová entita a není nutné vytvářet další podřízené certifikáty.
$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
Vytvoření podřízeného certifikátu z kořenového certifikátu
Podřízený certifikát lze také vytvořit přímo z kořenového certifikátu.
$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
Příklad kořenového certifikátu – zprostředkující certifikát – certifikát
$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
Při použití kořenových, zprostředkujících nebo podřízených certifikátů je možné certifikáty podle potřeby ověřit pomocí kryptografického otisku nebo klíče 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;
}
}
}
Ukládání certifikátů do mezipaměti
ASP.NET Core verze 5.0 a novější podporují možnost ukládání výsledků ověření do mezipaměti. Ukládání do mezipaměti výrazně zvyšuje výkon ověřování certifikátů, protože ověřování je nákladná operace.
Ve výchozím nastavení ověřování certifikátů ukládání do mezipaměti zakáže. Pokud chcete povolit ukládání do mezipaměti, AddCertificateCache volejte v Startup.ConfigureServices :
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(
CertificateAuthenticationDefaults.AuthenticationScheme)
.AddCertificate()
.AddCertificateCache(options =>
{
options.CacheSize = 1024;
options.CacheEntryExpiration = TimeSpan.FromMinutes(2);
});
}
Výchozí implementace ukládání do mezipaměti ukládá výsledky do paměti. Vlastní mezipaměť můžete poskytnout implementací a registrací pomocí ICertificateValidationCache injektáže závislostí. Například, services.AddSingleton<ICertificateValidationCache, YourCache>().
Volitelné klientské certifikáty
Tato část obsahuje informace pro aplikace, které musí chránit podmnožinu aplikace certifikátem. Například stránka nebo Razor kontroler v aplikaci může vyžadovat klientské certifikáty. To představuje problémy související s klientskými certifikáty:
- Jsou funkce PROTOKOLU TLS, nikoli funkce HTTP.
- Vyjednávají se pro každé připojení a obvykle na začátku připojení před tím, než jsou k dispozici data HTTP.
Existují dva přístupy k implementaci volitelných klientských certifikátů:
- Použití samostatných názvů hostitelů (SNI) a přesměrování Přestože je konfigurace větší, doporučuje se to, protože funguje ve většině prostředí a protokolů.
- Znovu se dosažte během požadavku HTTP. To má několik omezení a nedoporučuje se to.
Samostatní hostitelé (SNI)
Na začátku připojení je známá pouze Indikace názvu serveru † (SNI). Klientské certifikáty lze konfigurovat pro každý název hostitele tak, aby je jeden hostitel vyžádá a druhý nikoli.
- Nastavte vazbu pro doménu a subdoménu:
- Můžete například nastavit vazby pro a
contoso.commyClient.contoso.com. Hostitelcontoso.comnevyžaduje klientský certifikát, alemyClient.contoso.comano. - Další informace naleznete v tématu:
- Můžete například nastavit vazby pro a
- Nastavte vazbu pro doménu a subdoménu:
- Můžete například nastavit vazby pro a
contoso.commyClient.contoso.com. Hostitelcontoso.comnevyžaduje klientský certifikát, alemyClient.contoso.comano. - Další informace naleznete v tématu:
- Kestrelimplementace webového serveru v ASP.NET Core:
- ListenOptions.UseHttps
- ClientCertificateMode
- Poznámka: V současné době nepodporuje více konfigurací protokolu TLS u jedné vazby, budete potřebovat dvě vazby s Kestrel jedinečnými IP adresy nebo porty. Viz https://github.com/dotnet/runtime/issues/31097.
- IIS
- HTTP.sys: Konfigurace Windows serveru
- Kestrelimplementace webového serveru v ASP.NET Core:
- Můžete například nastavit vazby pro a
ASP.NET Core 5 a novější přidává pohodlnější podporu přesměrování za účelem získání volitelných klientských certifikátů. Další informace najdete v ukázce volitelných certifikátů.
- Pro požadavky na webovou aplikaci, které vyžadují klientský certifikát a nemají jeden:
- Přesměrovat na stejnou stránku pomocí subdomény chráněné klientským certifikátem.
- Můžete například přesměrovat na
myClient.contoso.com/requestedPage. Vzhledem k tomu, že požadavek na je jiný název hostitele než , klient navádí jiné připojení a klientskýmyClient.contoso.com/requestedPagecontoso.com/requestedPagecertifikát je k dispozici. - Další informace naleznete v tématu Úvod do autorizace v ASP.NET Core.
† Indikace názvu serveru (SNI) je rozšíření TLS, které zahrnuje virtuální doménu jako součást vyjednávání SSL. To v podstatě znamená, že název virtuální domény nebo název hostitele lze použít k identifikaci koncového bodu sítě.
Znovu se dojednání
Opětovné vyjednávání protokolu TLS je proces, pomocí kterého klient a server mohou znovu vyhodnotit požadavky na šifrování pro jednotlivá připojení, včetně žádosti o klientský certifikát, pokud nebyl dříve poskytnut. Nové vyjednávání o protokolu TLS je bezpečnostní riziko a nedoporučuje se, protože:
- V HTTP/1.1 musí server nejprve vyrovnávací paměť nebo spotřebovat jakákoli data HTTP, která letí, například těla požadavků POST, aby se ujistil, že je připojení jasné pro nové vyjednávání. Jinak může znovu vyjednávání přestat reagovat nebo selhat.
- HTTP/2 a HTTP/3 explicitně zakazují nové vyjednávání.
- S znovusjednáním souvisí bezpečnostní rizika. Protokol TLS 1.3 odebral nové vyjednávání celého připojení a nahradil ho novým rozšířením pro vyžádání pouze klientského certifikátu po zahájení připojení. Tento mechanismus se zveřejňuje prostřednictvím stejných rozhraní API a stále podléhá předchozím omezením ukládání do vyrovnávací paměti a verzí protokolu HTTP.
Implementace a konfigurace této funkce se liší podle verze serveru a architektury.
IIS
Služba IIS spravuje vyjednávání klientského certifikátu vaším jménem. Dílčí část aplikace může povolit možnost SslRequireCert vyjednat klientský certifikát pro tyto požadavky. Podrobnosti najdete v části Konfigurace v dokumentaci ke službě IIS.
Služba IIS automaticky uloží data textu požadavku do vyrovnávací paměti až do nakonfigurovaného limitu velikosti před tím, než se znovu projedná. Požadavky, které tento limit překročí, se zamítnou s odpovědí 413. Výchozí hodnota tohoto limitu je 48 MB a je možné ji nakonfigurovat nastavením parametru uploadReadAheadSize.
HttpSys
HttpSys má dvě nastavení, která řídí vyjednávání klientských certifikátů, a obě by se měly nastavit. První je v netsh.exe http add sslcert clientcertnegotation=enable/disable části . Tento příznak označuje, jestli se má klientský certifikát na začátku připojení nesnížovat, a měl by být nastavený na pro disable volitelné klientské certifikáty. Podrobnosti najdete v dokumentu netsh.
Druhé nastavení je ClientCertificateMethod . Pokud je nastavená na hodnotu , je možné během žádosti AllowRenegotation znovu projednat klientský certifikát.
POZNÁMKA: Aplikace by měla před pokusem o znovusjednání do vyrovnávací paměti nebo spotřebovat jakákoli data textu požadavku, jinak se může stát, že požadavek přestane reagovat.
Aplikace může nejprve zkontrolovat ClientCertificate vlastnost a zjistit, jestli je certifikát k dispozici. Pokud není k dispozici, před voláním pro vyjednání se ujistěte, že se spotřeboval GetClientCertificateAsync text požadavku. Poznámka: Pokud klient odmítne certifikát zadat, může GetClientCertificateAsync vrátit nulový certifikát.
POZNÁMKA: Chování vlastnosti se ClientCertificate v rozhraní .NET 6 změnilo, a podívejte se, https://github.com/aspnet/Announcements/issues/466 jestli pracujete s předchozími verzemi.
Existuje známý problém, kdy povolení může způsobit synchronní vyjednávání při AllowRenegotation přístupu k ClientCertificate vlastnosti. Pokud se GetClientCertificateAsync tomu chcete vyhnout, zavolejte metodu . Tento problém byl vyřešen v rozhraní .NET 6, viz https://github.com/aspnet/Announcements/issues/466 . Poznámka: Pokud klient odmítne certifikát zadat, může GetClientCertificateAsync vrátit nulový certifikát.
Kestrel
Kestrel řídí vyjednávání klientských certifikátů pomocí ClientCertificateMode možnosti .
Kestrel.Https.ClientCertificateMode.DelayCertificate je nová možnost dostupná v rozhraní .NET 6 nebo novějším. Při nastavení může aplikace zkontrolovat vlastnost ClientCertificate a zjistit, jestli je certifikát dostupný. Pokud není k dispozici, před voláním metody pro vyjednání se ujistěte, že se spotřeboval GetClientCertificateAsync text požadavku. Poznámka: Pokud klient odmítne certifikát zadat, může GetClientCertificateAsync vrátit nulový certifikát.
POZNÁMKA: Aplikace by před pokusem o znovusouzení měla do vyrovnávací paměti nebo spotřebovat jakákoli data textu požadavku, jinak GetClientCertificateAsync může vyvolat InvalidOperationExeption: Client stream needs to be drained before renegotiation. výjimku .
Pokud programově konfigurujete nastavení protokolu TLS na hostitele, je v .NET 6 a novějším k dispozici nové přetížení UseHttps, které přebírá a řídí opětovné vyjednávání klientských certifikátů Server.Kestrel.Https.TlsHandshakeCallbackOptions prostřednictvím Kestrel.Https.TlsHandshakeCallbackContext.AllowDelayedClientCertificateNegotation .
Pro .NET 5 a starší nepodporuje po zahájení připojení nové vyjednávání za účelem Kestrel získání klientského certifikátu. Tato funkce byla přidána v .NET 6.
Dotazy, komentáře a další připomínky k volitelným klientským certifikátům zanechte v tomto GitHub diskusi.