Jedna z možností, jak zabezpečit přístup k webové aplikaci, je ověřování pomoci klientského certifikátu. Ukážeme si postup jak toto ověření nastavit. Postup je možné použít nejen k ověření celé webové aplikace, ale i například k Web API rozhraní.
Nejprve k mému scénáři použití. Zákazník požadoval zpřístupnit personální data třetím stranám. Zhotovil jsem a vypublikoval webovou aplikaci, která pomoci HTTP handleru data poskytuje. Aplikace bude používat zabezpečený kanál pomoci HTTPS. Je ale více způsobů, jak zajistit ověření přístupu k této aplikaci. Windows (a ani basic) autentizace zde použít nešla, protože webová aplikace je provozovaná na počítači, kde nemáme přístup ke správě Windows uživatelů (jak doménových tak lokálních). Druhou možností by bylo použít Forms autentizaci. Když nepočítám to, že by aplikace nejspíše musela mít nějakou registraci a správu uživatelů, tak hlavní nevýhodou by bylo to, že by přístup vyžadoval zadávání loginu a hesla do přihlašovacího formuláře. Vzhledem k tomu, že k aplikací poskytovaným datům budou někteří klienti přistupovat nejspíše nějakým automatizovaným způsobem, je zadávání ověření do formuláře nevyhovující.
Protože klientů je relativně malý počet, rozhodl jsem se řešit přístup k aplikaci pomoci klientských certifikátů, a to tak, že každému klientovi, kterému chceme povolit přístup k datům, vygenerujeme vlastní certifikát. Tím zároveň budeme moci podle použitého certifikátu při přihlášení zjistit, který klient se přihlásil, případně podle toho zabezpečit přístup pouze k některým datům.
A nyní již k tomu jak jsem postupoval.
1) CA certifikát
Všechny certifikáty, které budeme klientům vytvářet budou vygenerované ze samostatné certifikační autority CA. Tu nemusíme nijak shánět nebo instalovat, pro tento scénář nám postačí pro autoritu pouze vygenerovat její vlastní certifikát. K tomu použijeme utilitu makecert.exe (dostupná ve Windows SDK). Příkaz pro vygenerování certifikátu CA je následující:
rem Vytvoření CA certifikátu
makecert -r -pe -n "CN=WebAccessCA" -ss CA -a sha1 -sky signature -cy authority -sv WebAccessCACert.pvk WebAccessCACert.cer
Při spuštění budeme dotázání na heslo (passphrase) pro vygenerování klíče. Já jsem si heslo vygeneroval pomoci http://chaos.aspnet.cz. Vzniknou nám soubory certifikátu WebAccessCACert.cer a privátního klíče WebAccessCACert.pvk.
Na počítači, kde webovou aplikaci hostujeme, naimportujeme soubor certifikátu certifikační autority WebAccessCACert.cer do Windows úložiště certifikátu Trusted Root Certification Authorities (Důvěryhodné kořenové certifikační úřady) pro Počítač – Local Computer.
2) Klientský certifikát
Druhým krokem bude vygenerování klientského certifikátu. Tento krok budeme používat opakovaně, při generování dalšího certifikátu novému klientovi. Opět použijeme makecert, navíc ale ještě pomoci pvk2pfx.exe převedeme soubory cer a pvk na soubor pfx.
rem Vytvoření Client certifikátu
makecert -pe -n "CN=Klient1" -a sha1 -sky exchange -eku 1.3.6.1.5.5.7.3.2 -ic WebAccessCACert.cer -iv WebAccessCACert.pvk -sv Klient1ClientCert.pvk Klient1ClientCert.cer
rem Převod souborů klíče pvk a certifikátu cer na pfx
pvk2pfx -pvk Klient1ClientCert.pvk -spc Klient1ClientCert.cer -pfx Klient1ClientCert.pfx -po MJAZWB!eAGoL
Při spuštění příkazu zadáme jak nové heslo pro klíč klientského certifikátu (opět můžeme vygenerovat), tak i původní heslo ke klíči CA certifikátu (Issuer Signature). Všimněte si dále v příkazu určení subjectu certifikátu (například CN=Klient1), podle něho pak budeme klienty rozeznávat.
Danému klientovi pak předáme soubor certifikační autority WebAccessCACert.cer a soubor klientského certifikátu ve formátu pfx Klient1ClientCert.pfx (a heslo k němu).
Na počítači klienta (nebo na vývojovém / testovacím počítači) poté provedeme tyto kroky:
1. Nainstalujeme certifikát Klient1ClientCert.pfx do Windows úložiště certifikátu Personal (Osobní) pro Uživatele – Current User.
2. Nainstalovat certifikát WebAccessCACert.cer do Windows úložiště certifikátu Trusted Root Certification Authorities (Důvěryhodné kořenové certifikační úřady) pro Počítač – Local Computer.
3. Nastavení IIS
Provedeme potřebné nastavení pro klientský certifikát na IIS. Předpokladem je dále nastavený HTTPS binding. V IIS manageru vybereme naší aplikaci a zvolíme SSL Settings.
Zapneme vyžadování SSL a dále zvolíme Require v nastavení Client certificates.
4. Ověření certifikátu v aplikaci
Pokud k aplikaci nyní budeme přistupovat z prohlížeče, budeme vyzvání k vybrání certifikátu, nabídnou se všechny validní certifikáty z Personal úložiště uživatele (a sem jsme právě klientský certifikát nainstalovali). Vybraný certifikát je v aplikaci dostupný pomoci vlastnosti ClientCertificate na Request objektu a to jestli byl certifikát zadán je možné zjistit vlastností IsPresent. Aplikace je nyní ale přístupná po vybrání jakéhokoliv platného certifikátu, co tedy dále budeme potřebovat bude zkontrolovat, zda se jedná o náš certifikát, který jsme dali klientovi.
V mém případě jsem kontrolu umístil přímo do handleru, který generuje data, ale bylo by možné jí umístit například do global.asax nebo samostatného modulu pro kontrolu všech requestů. Kód bude následující:
if (!HttpContext.Current.Request.ClientCertificate.IsPresent)
{
context.Response.StatusCode = 401;
context.Response.StatusDescription = "Unauthorized";
context.Response.End();
return;
}
var cert = new X509Certificate2(HttpContext.Current.Request.ClientCertificate.Certificate);
if (!this.IsValidCertificate(cert))
{
context.Response.StatusCode = 401;
context.Response.StatusDescription = "Unauthorized";
context.Response.End();
return;
}
var identity = new GenericIdentity(cert.Subject, "ClientCertificate");
var principal = new GenericPrincipal(identity, null);
Thread.CurrentPrincipal = principal;
HttpContext.Current.User = principal
Po ověření certifikátu je vytvořena Identita GenericIdentity, kde jako jméno použijeme Subject certifikátu.
Ještě nám zbývá implementovat metodu IsValidCertificate. Protože ale klientských certifikátu může být více, nemůžeme kontrolovat přímo předaný certifikát. Místo toho zkontrolujeme, zda byl certifikát vydaný z naší certifikační autority. Jinými slovy zkontrolujeme, že kořenový certifikát je náš WebAccessCACert.cer.
private bool IsValidCertificate(X509Certificate2 certificate)
{
var chain = new X509Chain();
chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
if (!chain.Build(certificate))
{
return false;
}
var caCert = chain.ChainElements[chain.ChainElements.Count - 1].Certificate;
return caCert.Thumbprint.Equals(Properties.Settings.Default.CACertificateThumbprint, StringComparison.OrdinalIgnoreCase);
}
Pomoci X509Chain se dostaneme k nadřazeným certifikátům. Pro kontrolu CA certifikátu jsem použil porovnání podle jeho Thumbprint, který jsem si zadal do konfigurace (přes generované Settings).
Tím je nyní handler dostupný pouze při přístupu certifikáty klientů vytvořeném v kroku 2.