Absicherung von Webdiensten mit 2FA: Zertifikat + Passwort
Einführung
- Zwei Faktoren: Besitz (Client-Zertifikat) und Wissen (Passwort).
- Der Server prüft das Client-Zertifikat gegen unsere CA (mTLS), danach folgt HTTP-Basic-Auth.
Ausgangspunkt
- Bestehender Apache-vHost gelb.it2XX.int (Debian) mit fertigem Server-Zertifikat
- Wenn vorhanden
- rm -v /var/www/gelb/.htaccess
- cat /etc/apache2/sites-available/gelb.conf
<VirtualHost *:443>
ServerName gelb.it2XX.int
DocumentRoot /var/www/gelb
SSLEngine on
SSLCertificateFile /etc/ssl/own.crt
SSLCertificateKeyFile /etc/ssl/own.key
<Directory /var/www/gelb>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/gelb_error.log
CustomLog ${APACHE_LOG_DIR}/gelb_access.log combined
</VirtualHost>
Auf dem CA-Host
Client-Zertifikat erstellen
#Variablen setzen
CA=it2XX-ca
USER=client
#CSR erzeugen
openssl req -new -newkey rsa:2048 -nodes -keyout $USER.key -out $USER.csr -subj "/CN=$USER"
#Signieren
openssl x509 -req -in $USER.csr -CA $CA.crt -CAkey $CA.key -CAcreateserial -out $USER.crt -days 365 -extfile <(printf "extendedKeyUsage=clientAuth")
#PKCS12 für den Browser-Import bauen (Export-Passwort setzen)
openssl pkcs12 -export -in $USER.crt -inkey $USER.key -certfile $CA.crt -out $USER.p12
Intermediate ca
#Root Zertifikat besorgen
wget https://web.samogo.de/certs/ca.crt
#CA Fullchain erzeugen
cat it213-ca.crt ca.crt > ca-fullchain.crt
Benutzer für Basic-Auth anlegen
- htpasswd -c /etc/apache2/.htpasswd martha
Apache-Konfiguration erweitern
- Die CA liegt bereits im System-Store, wir referenzieren die Datei direkt
- ls /usr/local/share/ca-certificates/
- cat /etc/apache2/sites-available/gelb.conf
<VirtualHost *:443>
ServerName gelb.it2XX.int
DocumentRoot /var/www/gelb
SSLEngine on
SSLCertificateFile /etc/ssl/own.crt
SSLCertificateKeyFile /etc/ssl/own.key
SSLCACertificateFile /etc/ssl/ca-fullchain.crt
SSLVerifyDepth 2
SSLVerifyClient require
<Directory /var/www/gelb>
Options Indexes FollowSymLinks
AllowOverride All
AuthType Basic
AuthName "Login mit Benutzername und Passwort"
AuthUserFile /etc/apache2/.htpasswd
Require valid-user
</Directory>
ErrorLog ${APACHE_LOG_DIR}/gelb_error.log
CustomLog ${APACHE_LOG_DIR}/gelb_access.log combined
</VirtualHost>
- Config testen und neu laden
- apachectl configtest
- systemctl reload apache2
Zertifikat im Firefox einbinden
- Import
- Firefox → Einstellungen → Datenschutz & Sicherheit → Zertifikate anzeigen
- Reiter "Ihre Zertifikate" → Importieren → client.p12 (Export-Passwort eingeben)
- Verwendung
Test
- Kein Zertifikat
- TLS-Handshake-Fehler (curl: alert certificate required, kein HTTP-Fehlercode)
- Falsches Passwort
- Zertifikat + Passwort korrekt
- Test mit curl
Optional: Nur bestimmten CN zulassen
- SSLVerifyClient prüft nur die Signatur der CA – jedes von ihr ausgestellte Zertifikat wird akzeptiert.
- Im Directory-Block ergänzen
Require expr "%{SSL_CLIENT_S_DN_CN} == 'client'"
- Testfall
- gültiges Zertifikat, falscher CN
Fazit
- mTLS plus Basic-Auth ergibt eine echte 2-Faktor-Absicherung: Besitz und Wissen.
- SSLCACertificateFile bestimmt, wessen Client-Zertifikate akzeptiert werden – einen Default auf den System-Store gibt es bewusst nicht.