Identifikace klientskými certifikáty na serveru Apache

DanielBlack

/!\

Tento článek předpokládá, že jste si pro Apache stáhli kořenové certifikáty CAcert do souborů root.crt a class3.crt. Nové kořenové certifikáty CAcert si však stahujete jako soubory root_X0F.crt nebo class3_x14E228.crt, kde číslo za X je hexadecimální pořadové číslo nových kořenových certifikátů CAcert (15 a 1 368 616). Nejjednodušší je přejmenovat tyto stažené soubory s novými kořenovými certifikáty původními jmény uvedenými v dalším textu článku.

/!\

Klientská strana identifikace u Apache není založena na dokumentaci httpd mod_ssl a byla použita v řadě systémů CACert, jako seznamy a webmail (pro štáb). Konfigurace Apache pro identifikaci klientské strany by se měly objevit ve směrnici VirtualHost, ačkoli mohou existovat podle jiných směrnic, jako Umístění. Tyto direktivy jsou doplněny ke konfiguraci SSL serveru, ačkoli raději používám SSLCACertificatePath a nepoužívám SSLCertificateChainFile.

Základní identifikace klientské strany

Toto je pro případ, že chceme, aby byl web přístupný pouze certifikátem. V tomto případě jakýmkoli certifikátem ze sady CA.

SSLCADNRequestPath obsahuje cestu certifikátů, které bude tento web přijímat. To bude potřebné ve formátu openssl obsahujícím odkazy z subject_hash do souboru viz dále. Balíčky openssl obsahují skript rehash nebo c_rehash, který je může vygenerovat použitím příkazu c_rehash /usr/share/ca-certificates/cacert.org/.

Všimněte si výše, že jsem napsal direktivu SSLVerifyClient optional (SSLVerifyClient nepovinný). To je kvůli chybové hlášce při SSLVerifyClient required (SSLVerifyClient povinný) a osoba bez instalovaného certifikátového přístupu k webu je spíše neintuitivní (Firefox - požadavek na zlepšení). Jednoduché direktivy Rewrite na konci znamenají, že je stránka zakázaná s chybou jako při ErrorDocument. Budete potřebovat instalovat a povolit mod_rewrite, abyste to mohli použít.

Povolit určité certifikáty - podle seznamu

K výše uvedeným direktivám přidáme:

Přitom /var/www/.htpasswd se podobá:

Část s heslem xxj31ZMTZzkVA je vždy stejná. První část obdržíte příkazem openssl x509 -noout -subject -in certificate.crt, kde certificate.crt je certifikát, kterému chcete udělit přístup.

Povolit určité certifikáty - výrazem

Někdy potřebujete říci: ano, přijmi jakýkoli certifikát z CAcertu, který nese e-mailovou adresu @example.com a nestarej se o udržování dlouhých seznamů. To je možné takto:

SSLRequire %{SSL_CLIENT_S_DN_Email} =~ m/^[^@]*@example\.com$/

Celý seznam je zde: http://httpd.apache.org/docs/trunk/mod/mod_ssl.html#sslrequire. Některé certifikáty obsahují více e-mailových adres než jednu, takže:

Měli byste také změnit chybové hlášení (viz výše), aby oznámilo, že certifikáty pro @example.com se také požadují.

Žurnálové soubory (logfiles)

Standardní kombinovaný žurnálový soubor (logfile) v Apache má pole pro uživatelské jméno (username), to se však při používání klientských certifikátů nevyužívá. Udržovat žurnál ve stejném formátu je však vhodná, pokud jej budete někdy chtít analyzovat, aniž musíte přizpůsobit analyzující software.

Použijte tedy CustomLog s kombinovaným formátem žurnálu a změňte %u (username) na e-mailovou adresu %{SSL_CLIENT_S_DN_Email} (nebo jinou proměnnou dle SSL_CLIENT*, která Vám bude užitečná).

Identifikace ve webových aplikacích

Řada webových aplikací může použít proměnnou prostředí REMOTE_USER pro řízení přístupu do různých částí webové aplikace. Tyto webové aplikace obvykle popisují použití této schopnosti s identifikací Apache Basic nebo Apache Digest. Můžete zde použít SSL certifikáty.

Použijte možnost SSL SSLUserName s proměnnou prostředí obsahující jméno uživatele (username): Proměnné prostředí. SSL_CLIENT_S_DN_Email je užitečná, ačkoli záleží na webové aplikaci a uživatelích, zda je přípustné používat e-mail jako uživatelské jméno.

CustomLog /var/log/apache2/ssl_access.log  "%h %l %{SSL_CLIENT_S_DN_Email}x %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\""

Kontrola odvolaných certifikátů

OCSP (Online Certificate Status Protocol, protokol stavu certifikátů on-line) se dá použít ke kontrole, zda nebyly certifikáty odvolány. To mohou za Vás kontrolovat jen verze Apache 2.3 a vyšší (OCSPEnable).

Používáte-li Apache verze 2.2 nebo nižší, budete muset použít ke kontrole odvolání CRL, protože tyto verze nepodporují OCSP. Musíte tedy vytvořit úlohu pro cron, která stáhne aktuální CRL a nastaví Apache na jeho použití:

  1. Vytvořte adresář, kam se CRL uloží. Obvykle je dobré místo /var/local/ssl/crls.

  2. Vytvořte úlohu cron, která CRL stáhne. Připravil jsem shell script, který jenom uložíte do /etc/cron.hourly (nebo daily nebo jinak). Skript vyžaduje rsync, c_rehash utilitu z openssl a závisí na service apache2 reload k opětnému zavedení konfigurace Apache. Upravte ho podle svých potřeb, máte-li nastavení, které nevykazuje tyto závislosti.

  3. Do konfigurace Apache dejte:
  4. SSLCARevocationPath /var/local/ssl/crls/

  5. Poprvé spusťte skript úlohy cron - zároveň zavede novou konfiguraci Apache.
  6. Zkontrolujte, zda všechno správně funguje.


Příspěvky a úvahy

24.05.2010-UlrichSchroeter

Win32 (s Cygwin) podrobnosti implementace:

1.)

Openssl rehash, ani c_rehash, ani perl skript c_rehash mi nefungují. Ani Sysinternals Junction, ani jiná řešení nedělají, co očekávám. Po dvou dnech neúspěchů jsem přestal hledat, jak to obejít, a rozhodl jsem se vytvořit dvě základní části skriptů ručně z příkazového řádku DOS:

$>openssl x509 -noout -hash <root.crt
  poznamenal jsem si výsledek haše a přidal ho do následujícího příkazového řádku Cygwin, příkazu ln
$>ln --symbolic --no-target-directory root.crt 5ed36f99.0
  (poslední argument)
$>openssl x509 -noout -hash <class3.crt
  poznamenal jsem si výsledek haše a přidal ho do následujícího příkazového řádku Cygwin, příkazu ln:
$>ln --symbolic --no-target-directory class3.crt e5662767.0
  (poslední argument)
Poznámka: příkaz 'ln' se v Cygwin používá s jinou syntaxí.

2.)

SSLRequire mi nefunguje pod Apache/2.2.11 (Win32) mod_ssl/2.2.11 OpenSSL/0.9.8e ...
Konfigurační syntaxi pro Apache:
SSLRequire %{SSL_CLIENT_S_DN_Email} =~ m/^[^@]*@example\.com$/
          or %{SSL_CLIENT_S_DN_Email_0} =~ m/^[^@]*@example\.com$/
          or %{SSL_CLIENT_S_DN_Email_1} =~ m/^[^@]*@example\.com$/
          or %{SSL_CLIENT_S_DN_Email_2} =~ m/^[^@]*@example\.com$/
          or %{SSL_CLIENT_S_DN_Email_3} =~ m/^[^@]*@example\.com$/
musím změnit na:
SSLRequire ( (%{SSL_CLIENT_S_DN_Email} in {"alias@example.com"}) or (%{SSL_CLIENT_S_DN_Email} in {"alias2@example.com"}) )
všechno v jednom řádku, části jsou v kulatých závorkách (), jinak vždy dostanu při startu služby chyby:
   "The Apache service terminated with service-specific error 1" (Služba Apache ukončena chybou 1)
nebo chyby spojení:
   "failed, reason: SSL requirement expression not fulfilled" (selhalo, důvod: výraz požadovaný SSL není vyplněn)

3.)

do http.conf jsem přidal základní definice pro Alias:
Alias /users/ "D:/Apache/Apache2/wwwroot2/users"
<Directory "D:/Apache/Apache2/wwwroot2/users">
  SSLOptions +FakeBasicAuth +StdEnvVars +ExportCertData
    Options Indexes MultiViews
    AllowOverride None
    Order allow,deny
    Allow from all
</Directory>

a do ssl.conf jsem přidal příkaz SSLrequire do sekce location:
<Location /user1/>
 SSLRequire (( ( %{SSL_CLIENT_S_DN_Email} in {"alias@example.com"} ) or ( %{SSL_CLIENT_S_DN_Email} in {"alias2@example.com"}) ) and ( %{SSL_CLIENT_V_REMAIN} > 0 ) and (( %{SSL_CLIENT_I_DN_CN} in {"CA Cert Signing Authority"}) or ( %{SSL_CLIENT_I_DN_CN} in {"CAcert Class 3 Root"}) ))
</Location>

Příkaz SSLRequire musí být celý na jednom řádku (!) (viz bod 2)
SSL_CLIENT_V_REMAIN kontroluje klientský certifikát, zda už nevypršel. SSL_CLIENT_I_DN_CN kontroluje kořenový (třídy 1) a zprostředkující (třídy 3) údaj vydavatele CAcert v klientských certifikátech.

s úctou Uli ;-)


21.05.2011-u60

skript běžící jednou týdně nebo jednou za dva týdny (s instalovanými cygwin)

wget -nc http://crl.cacert.org/revoke.crl
wget -nc http://crl.cacert.org/class3-revoke.crl

rem  for all 0 files  delete old hash 0 files

for %%a in (*.r0.lnk) do attrib -R %%a
for %%a in (*.r0.lnk) do del %%a

openssl crl -in revoke.crl -inform DER -out revoke-cacert_root_now.crl -outform PEM
openssl crl -noout -hash<revoke-cacert_root_now.crl>temphash.tmp
set /p hash= <temphash.tmp
ln --symbolic --no-target-directory revoke-cacert_root_now.crl %hash%.r0

openssl crl -in class3-revoke.crl -inform DER -out revoke-cacert_class3_now.crl -outform PEM
openssl crl -noout -hash<revoke-cacert_class3_now.crl>temphash.tmp
set /p hash= <temphash.tmp
ln --symbolic --no-target-directory revoke-cacert_class3_now.crl %hash%.r0

## nezapomeňte restartovat Apache démona / službu


27.05.2011-u60

Pro kontrolu na úrovni aplikace pomocí php nad Apache si musíte trochu zaprogramovat v php.
Příklad je v tomto článku:


02.06.2011-u60

Konfigurace pro smíšené prostředí "klientské certifikáty vyžadovány" / "klientské certifikáty nevyžadovány"

1. Konfigurujte svůj https server Apache, aby standardně nepožadoval klientské certifikáty kromě určitých částí:
   /secure/     část vyžadující klientské certifikáty
   /unsecure/   část, kde se klientské certifikáty nevyžadují, také sem dát "přistávací" stránku
   /other/      pokud mají být ostatní adresáře povinně zabezpečeny klientskými certifikáty,
                přidejte do httpd.conf direktivu <adresář ..> jako pro /secure/,
                přidejte do .htaccess jako níže v příkladu /secure/.htaccess

httpd.conf
.........................................
[...]
# standardní port 80 - konfigurace
                                                 
/secure/.htaccess
<Directory .../WWWROOT/secure/>                  
......................................
# 
#Trvalá redirekce                              
RewriteEngine on
# 
#z http://../secure/.*                         
RewriteCond %{SERVER_PORT} !^443$
# 
#do     //../unsecure/index.php                
RewriteRule ^(.*)$ /unsecure/index.php [R=301,L]
    AllowOverride All                            
......................................
</Directory>

[...]
<IfModule mod_ssl.c>
    Include conf/ssl.conf
</IfModule>
[...]
.........................................


ssl.conf
.........................................
<VirtualHost _default_:443>
SSLEngine on
SSLVerifyDepth 3

#Klíče serveru
SSLCertificateFile     /Apache/Apache2/conf/ssl.crt/your-pub-server-key.pem
SSLCertificateKeyFile  /Apache/Apache2/conf/ssl.key/your-private-server-key.pem
#Ověření souboru klíčů serveru proti CA
SSLCertificateChainFile /Apache/Apache2/conf/ssl.crt/cacert-chain.pem

# Před-definice ověření klientských certifikátů, která je potřebná v dalších direktivách <directory ..>
SSLCACertificateFile /Apache/Apache2/conf/cacert.org/root.crt
SSLCACertificatePath I:/Apache/Apache2/conf/ssl.vrf/
SSLCADNRequestPath /Apache/Apache2/conf/ssl.vrf/

#   Certificate Revocation Lists (CRL):
SSLCARevocationFile /Apache/Apache2/conf/ssl.crl/revoke-cacert_root.crl
SSLCARevocationFile /Apache/Apache2/conf/ssl.crl/revoke-cacert_class3.crl

#  EOT standardních definic


#  KLIENTSKÉ CERTIFIKÁTY NEVYŽADOVÁNY
<Directory /unsecure/>
###  Ověření klienta NE
SSLVerifyClient none
</Directory>

# KLIENTSKÉ CERTIFIKÁTY VYŽADOVÁNY
<Directory /Apache/Apache2/WWWROOT/secure/>
##  SSLRequireSSL
### Ověření klienta
SSLVerifyClient require
SSLVerifyDepth 3
#SSLCADNRequestPath /Apache/Apache2/conf/ssl.vrf/   viz předkonfigurace

SSLRequire ( ( %{SSL_CLIENT_V_REMAIN} > 0 ) and (( %{SSL_CLIENT_I_DN_CN} in {"CA Cert Signing Authority"}) or ( %{SSL_CLIENT_I_DN_CN} in {"CAcert Class 3 Root"}) ))

### ošetření chyb
RewriteEngine        on
RewriteCond     %{SSL:SSL_CLIENT_VERIFY} !=SUCCESS
RewriteRule     .? - [F]
ErrorDocument 403 "You need a valid client certificate from CAcert.Org to access this page on this site."
 (Pro přístup k této stránce na tomto webu potřebujete mít platný certifikát od CAcert.org.)
</Directory>

</VirtualHost>
.........................................


php scripty

/unsecure/index.php
.........................................
[...]
<script language="javascript" type="text/javascript">
<!--
function $(id) { return document.getElementById(id); }
// -->
</script>
[...]
Description/Warning: You need a valid client cert installed in your browser to continue with client cert login
 (Popis/Varování: Pro pokračování v přihlášení klientským certifikátem potřebujete mít v prohlížeči instalován platný klientský certifikát.)
[...]
<form action="https://../secure/login.php" method="post" id="login">
<input type="submit" value="Cert Login">
<button onclick="$('login').action='/unsecure/cancel-infopage.html';$('login').submit();">Cancel</button>
</form>
[...]
.........................................


/secure/login.php
.........................................
<?php

$user = $_SERVER["SSL_CLIENT_S_DN_CN"];
$email = $_SERVER["SSL_CLIENT_S_DN_Email"];
$server = $_SERVER["SSL_SERVER_S_DN_CN"];
$clisscert = $_SERVER["SSL_CLIENT_I_DN_CN"];

if ($_SERVER["SSL_CLIENT_VERIFY"]!="SUCCESS") {
  header ("Location: /unsecure/index.php");
  exit;
} else {
?>
[html kód sem]
[...]
<h2>Úspěšné přihlášení klientským certifikátem</h2>

<p>Nazdar <?php echo $user; ?>,<br>
Úspěšně jste se přihlásil k <?php echo $server; ?><br>
svým klientským certifikátem vydaným 
<?php
if ($clisscert=="CAcert Class 3 Root") {
 echo $clisscert." (zprostředkujícím certifikátem třídy 3)";
} else {
 echo $clisscert." (kořenovým certifikátem třídy 1)";
} 
?>.<br>
<br>
Tuto stránku vidíte jen po úspěšné identifikaci platným klientským certifikátem.<br>
Nyní máte povolen přístup do oblastí s omezeným přístupem na základě klientského certifikátu.<br>
Klidně pokračujte ve své cestě tímto webem...</p>

</body>
</html>
<?php
}
?>
.........................................


YYYYMMDD-YourName (Vaše_jméno)

Text / Vaše příspěvky, úvahy a úryvky e-mailů, prosím


Technology/KnowledgeBase/Server/ApacheServerClientCertificateAuthentication/CZ (last edited 2021-07-14 11:05:50 by AlesKastner)