Nginx Client Zertifikat: Unterschied zwischen den Versionen
Zur Navigation springen
Zur Suche springen
(Die Seite wurde neu angelegt: „=Absicherung von Webdiensten mit 2FA: Zertifikat + Passwort= ==Voraussetzungen== ;Zertifikate * Eine eigene CA: ca.crt * Ein Server-Zertifikat: server.crt und…“) |
|||
| (3 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt) | |||
| Zeile 1: | Zeile 1: | ||
| − | =Absicherung von Webdiensten mit 2FA: Zertifikat + Passwort= | + | =Absicherung von Webdiensten mit 2FA: Zertifikat + Passwort (Nginx)= |
| − | + | ==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 Nginx-vHost secure.it2XX.int (Debian) mit fertigem Server-Zertifikat | |
| − | * | + | ;Wenn vorhanden |
| − | + | *rm -v /var/www/secure/.htaccess | |
| − | + | *cat /etc/nginx/sites-available/secure.conf | |
| − | + | <pre> | |
| − | |||
| − | == | ||
| − | * | ||
| − | |||
| − | |||
server { | server { | ||
listen 443 ssl; | listen 443 ssl; | ||
| − | server_name secure. | + | listen [::]:443 ssl; |
| − | + | server_name secure.it2XX.int; | |
| − | ssl_certificate /etc/nginx/ssl/ | + | root /var/www/secure; |
| − | ssl_certificate_key /etc | + | index index.html; |
| − | + | ssl_certificate /etc/ssl/own.crt; | |
| − | ssl_client_certificate /etc | + | ssl_certificate_key /etc/ssl/own.key; |
| + | location / { | ||
| + | try_files $uri $uri/ =404; | ||
| + | } | ||
| + | } | ||
| + | </pre> | ||
| + | ==Auf dem CA-Host== | ||
| + | ===Client-Zertifikat erstellen=== | ||
| + | *cd ~/intermediate-ca | ||
| + | <pre> | ||
| + | #Variablen setzen | ||
| + | CA=it2XX-ca | ||
| + | USER_B=client | ||
| + | #CSR erzeugen | ||
| + | openssl req -new -newkey rsa:2048 -nodes -keyout $USER_B.key -out $USER_B.csr -subj "/CN=$USER_B" | ||
| + | #Signieren | ||
| + | openssl x509 -req -in $USER_B.csr -CA $CA.crt -CAkey $CA.key -CAcreateserial -out $USER_B.crt -days 365 -extfile <(printf "extendedKeyUsage=clientAuth") | ||
| + | #PKCS12 für den Browser-Import bauen (Export-Passwort setzen) | ||
| + | openssl pkcs12 -export -in $USER_B.crt -inkey $USER_B.key -certfile $CA.crt -out $USER_B.p12 | ||
| + | </pre> | ||
| + | ;$USER_B.p12 muss zum Client | ||
| + | ===Intermediate CA Fullchain=== | ||
| + | <pre> | ||
| + | #Root-Zertifikat besorgen | ||
| + | wget https://web.samogo.de/certs/ca.crt | ||
| + | #CA-Fullchain erzeugen | ||
| + | cat it2XX-ca.crt ca.crt > ca-fullchain.crt | ||
| + | </pre> | ||
| + | ;ca-fullchain.crt muss zum Webserver | ||
| + | ==Benutzer für Basic-Auth anlegen== | ||
| + | *htpasswd -c /etc/nginx/.htpasswd martha | ||
| + | ==Nginx-Konfiguration erweitern== | ||
| + | *cat /etc/nginx/sites-available/secure.conf | ||
| + | <pre> | ||
| + | server { | ||
| + | listen 443 ssl; | ||
| + | listen [::]:443 ssl; | ||
| + | server_name secure.it2XX.int; | ||
| + | root /var/www/secure; | ||
| + | index index.html; | ||
| + | ssl_certificate /etc/ssl/own.crt; | ||
| + | ssl_certificate_key /etc/ssl/own.key; | ||
| + | ssl_client_certificate /etc/ssl/ca-fullchain.crt; | ||
ssl_verify_client on; | ssl_verify_client on; | ||
| − | |||
ssl_protocols TLSv1.2 TLSv1.3; | ssl_protocols TLSv1.2 TLSv1.3; | ||
| − | |||
location / { | location / { | ||
auth_basic "Login mit Benutzername und Passwort"; | auth_basic "Login mit Benutzername und Passwort"; | ||
auth_basic_user_file /etc/nginx/.htpasswd; | auth_basic_user_file /etc/nginx/.htpasswd; | ||
| − | + | try_files $uri $uri/ =404; | |
| − | |||
| − | |||
} | } | ||
} | } | ||
| − | + | </pre> | |
| + | ;Config testen und neu laden | ||
| + | *nginx -t | ||
| + | *systemctl reload nginx | ||
==Zertifikat im Firefox einbinden== | ==Zertifikat im Firefox einbinden== | ||
;Import | ;Import | ||
* Firefox → Einstellungen → Datenschutz & Sicherheit → Zertifikate anzeigen | * Firefox → Einstellungen → Datenschutz & Sicherheit → Zertifikate anzeigen | ||
| − | * Reiter "Ihre Zertifikate" → Importieren → client.p12 | + | * Reiter "Ihre Zertifikate" → Importieren → client.p12 (Export-Passwort eingeben) |
| − | |||
;Verwendung | ;Verwendung | ||
| − | * Seite aufrufen: https://secure. | + | * Seite aufrufen: https://secure.it2XX.int |
* Firefox fragt nach Zertifikat → dann HTTP-Login | * Firefox fragt nach Zertifikat → dann HTTP-Login | ||
| − | |||
==Test== | ==Test== | ||
;Kein Zertifikat | ;Kein Zertifikat | ||
| − | * Fehler | + | * TLS-Handshake-Fehler (curl: alert certificate required, kein HTTP-Fehlercode) |
| − | |||
;Falsches Passwort | ;Falsches Passwort | ||
* Fehler 401 | * Fehler 401 | ||
| − | |||
;Zertifikat + Passwort korrekt | ;Zertifikat + Passwort korrekt | ||
* Zugriff erlaubt | * Zugriff erlaubt | ||
| + | ;Test mit curl | ||
| + | *curl --cert client.crt --key client.key -u martha https://secure.it2XX.int | ||
| + | ==Optional: Nur bestimmten CN zulassen== | ||
| + | * ssl_verify_client prüft nur die Signatur der CA – jedes von ihr ausgestellte Zertifikat wird akzeptiert. | ||
| + | ;Im location-Block ergänzen | ||
| + | <pre> | ||
| + | if ($ssl_client_s_dn !~ "CN=client") { | ||
| + | return 403; | ||
| + | } | ||
| + | </pre> | ||
| + | ;Testfall: gültiges Zertifikat, falscher CN | ||
| + | * Fehler 403 | ||
| + | ==Fazit== | ||
| + | * mTLS plus Basic-Auth ergibt eine echte 2-Faktor-Absicherung: Besitz und Wissen. | ||
| + | * ssl_client_certificate bestimmt, wessen Client-Zertifikate akzeptiert werden. | ||
Aktuelle Version vom 12. Juni 2026, 12:40 Uhr
Absicherung von Webdiensten mit 2FA: Zertifikat + Passwort (Nginx)
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 Nginx-vHost secure.it2XX.int (Debian) mit fertigem Server-Zertifikat
- Wenn vorhanden
- rm -v /var/www/secure/.htaccess
- cat /etc/nginx/sites-available/secure.conf
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name secure.it2XX.int;
root /var/www/secure;
index index.html;
ssl_certificate /etc/ssl/own.crt;
ssl_certificate_key /etc/ssl/own.key;
location / {
try_files $uri $uri/ =404;
}
}
Auf dem CA-Host
Client-Zertifikat erstellen
- cd ~/intermediate-ca
#Variablen setzen CA=it2XX-ca USER_B=client #CSR erzeugen openssl req -new -newkey rsa:2048 -nodes -keyout $USER_B.key -out $USER_B.csr -subj "/CN=$USER_B" #Signieren openssl x509 -req -in $USER_B.csr -CA $CA.crt -CAkey $CA.key -CAcreateserial -out $USER_B.crt -days 365 -extfile <(printf "extendedKeyUsage=clientAuth") #PKCS12 für den Browser-Import bauen (Export-Passwort setzen) openssl pkcs12 -export -in $USER_B.crt -inkey $USER_B.key -certfile $CA.crt -out $USER_B.p12
- $USER_B.p12 muss zum Client
Intermediate CA Fullchain
#Root-Zertifikat besorgen wget https://web.samogo.de/certs/ca.crt #CA-Fullchain erzeugen cat it2XX-ca.crt ca.crt > ca-fullchain.crt
- ca-fullchain.crt muss zum Webserver
Benutzer für Basic-Auth anlegen
- htpasswd -c /etc/nginx/.htpasswd martha
Nginx-Konfiguration erweitern
- cat /etc/nginx/sites-available/secure.conf
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name secure.it2XX.int;
root /var/www/secure;
index index.html;
ssl_certificate /etc/ssl/own.crt;
ssl_certificate_key /etc/ssl/own.key;
ssl_client_certificate /etc/ssl/ca-fullchain.crt;
ssl_verify_client on;
ssl_protocols TLSv1.2 TLSv1.3;
location / {
auth_basic "Login mit Benutzername und Passwort";
auth_basic_user_file /etc/nginx/.htpasswd;
try_files $uri $uri/ =404;
}
}
- Config testen und neu laden
- nginx -t
- systemctl reload nginx
Zertifikat im Firefox einbinden
- Import
- Firefox → Einstellungen → Datenschutz & Sicherheit → Zertifikate anzeigen
- Reiter "Ihre Zertifikate" → Importieren → client.p12 (Export-Passwort eingeben)
- Verwendung
- Seite aufrufen: https://secure.it2XX.int
- Firefox fragt nach Zertifikat → dann HTTP-Login
Test
- Kein Zertifikat
- TLS-Handshake-Fehler (curl: alert certificate required, kein HTTP-Fehlercode)
- Falsches Passwort
- Fehler 401
- Zertifikat + Passwort korrekt
- Zugriff erlaubt
- Test mit curl
- curl --cert client.crt --key client.key -u martha https://secure.it2XX.int
Optional: Nur bestimmten CN zulassen
- ssl_verify_client prüft nur die Signatur der CA – jedes von ihr ausgestellte Zertifikat wird akzeptiert.
- Im location-Block ergänzen
if ($ssl_client_s_dn !~ "CN=client") {
return 403;
}
- Testfall
- gültiges Zertifikat, falscher CN
- Fehler 403
Fazit
- mTLS plus Basic-Auth ergibt eine echte 2-Faktor-Absicherung: Besitz und Wissen.
- ssl_client_certificate bestimmt, wessen Client-Zertifikate akzeptiert werden.