Crmgo Blog

Nginx SSL

Nginx SSL

Um einen HTTPS-Server einzurichten, muss die Option `ssl` für die lauschenden Sockets im `server`-Block aktiviert sowie der Pfad zu den Dateien mit dem Serverzertifikat und dem geheimen Schlüssel angegeben werden: Das Serverzertifikat ist öffentlich. Es wird an jeden Client gesendet, der eine Verbindung zum Server herstellt. Der geheime Schlüssel sollte …

Nginx SSL

Um einen HTTPS-Server einzurichten, muss die Option ssl in den Listening-Sockets im server-Block aktiviert sowie der Pfad zu den Dateien mit dem Serverzertifikat und dem geheimen Schlüssel angegeben werden:

server {
    listen              443 ssl;
    server_name         www.example.com;
    ssl_certificate     www.example.com.crt;
    ssl_certificate_key www.example.com.key;
    ssl_protocols       SSLv3 TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers         HIGH:!aNULL:!MD5;
    ...
}

Das Serverzertifikat ist öffentlich. Es wird an jeden Client gesendet, der eine Verbindung zum Server herstellt. Der geheime Schlüssel sollte in einer Datei mit eingeschränktem Zugriff gespeichert werden (die Zugriffsrechte müssen es dem Hauptprozess von nginx ermöglichen, diese Datei zu lesen). Der geheime Schlüssel kann auch in derselben Datei wie das Zertifikat gespeichert werden:

    ssl_certificate     www.example.com.cert;
    ssl_certificate_key www.example.com.cert;

Dabei sollten die Zugriffsrechte auf die Datei ebenfalls eingeschränkt werden. Obwohl sowohl das Zertifikat als auch der Schlüssel in einer Datei gespeichert sind, wird an den Client nur das Zertifikat gesendet.

Mit den Direktiven ssl_protocols und ssl_ciphers können Verbindungen so eingeschränkt werden, dass nur „starke“ Versionen und Chiffren von SSL/TLS verwendet werden. Ab Version 1.0.5 verwendet nginx standardmäßig „ssl_protocols SSLv3 TLSv1“ und „ssl_ciphers HIGH:!aNULL:!MD5“, daher ist eine explizite Konfiguration nur für ältere Versionen von nginx sinnvoll. Ab den Versionen 1.1.13 und 1.0.12 verwendet nginx standardmäßig „ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2“.

Bekanntermaßen sind Chiffren im CBC-Modus anfällig für eine Reihe von Angriffen, insbesondere für die BEAST-Attacke (siehe CVE-2011-3389). Die Konfiguration der Chiffren kann so geändert werden, dass RC4-SHA bevorzugt wird:

    ssl_ciphers RC4:HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

 

 

Optimierung des HTTPS-Servers

SSL-Operationen verbrauchen zusätzliche CPU-Ressourcen. Auf Multiprozessorsystemen sollten mehrere Worker-Prozesse gestartet werden, mindestens so viele wie verfügbare CPU-Kerne vorhanden sind. Die ressourcenintensivste Operation für die CPU ist der SSL-Handshake, bei dem die kryptografischen Parameter der Sitzung erstellt werden. Es gibt zwei Möglichkeiten, die Anzahl dieser pro Client durchgeführten Operationen zu reduzieren: die Verwendung von Keepalive-Verbindungen, die es ermöglichen, mehrere Anfragen innerhalb einer einzigen Verbindung zu bearbeiten, und die Wiederverwendung der SSL-Sitzungsparameter, um zu verhindern, dass für parallele und nachfolgende Verbindungen ein SSL-Handshake durchgeführt werden muss. Sitzungen werden im SSL-Sitzungscache gespeichert, der zwischen den Worker-Prozessen geteilt wird und mit der Direktive ssl_session_cache konfiguriert wird. In 1 Megabyte Cache können etwa 4000 Sitzungen gespeichert werden. Die Standard-Timeout-Zeit des Caches beträgt 5 Minuten. Sie kann mit der Direktive ssl_session_timeout erhöht werden. Hier ist ein Beispiel für eine Konfiguration, die für ein Mehrkernsystem mit einem 10-Megabyte-großen gemeinsamen Sitzungscache optimiert ist:

worker_processes auto;

http {
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;

    server {
        listen              443 ssl;
        server_name         www.example.com;
        keepalive_timeout 70;

        ssl_certificate     www.example.com.crt;
        ssl_certificate_key www.example.com.key;
        ssl_protocols       SSLv3 TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers         HIGH:!aNULL:!MD5;
        ...

 

 

SSL-Zertifikatsketten

Einige Browser können eine Warnung bezüglich eines Zertifikats anzeigen, das von einer allgemein bekannten Zertifizierungsstelle (CA) signiert wurde, während andere Browser dasselbe Zertifikat ohne Probleme akzeptieren. Dies geschieht, weil die ausstellende CA das Zertifikat mit einem Zwischenzertifikat signiert hat, das nicht in der mit dem Browser verteilten Datenbank der allgemein bekannten vertrauenswürdigen Zertifizierungsstellen enthalten ist. In einem solchen Fall stellt die Zertifizierungsstelle einen „Zertifikatsbund“ bereit, der an das Serverzertifikat angehängt werden sollte. Das Serverzertifikat muss vor dem Zertifikatsbund in der kombinierten Datei platziert werden:

$ cat www.example.com.crt bundle.crt > www.example.com.chained.crt

Die resultierende Datei ist in der Direktive ssl_certificate anzugeben:

server {
    listen              443 ssl;
    server_name         www.example.com;
    ssl_certificate     www.example.com.chained.crt;
    ssl_certificate_key www.example.com.key;
    ...
}

Wenn das Serverzertifikat und der Zertifikatsbund in der falschen Reihenfolge verbunden wurden, weigert sich nginx, zu starten, und gibt eine Fehlermeldung aus:

SSL_CTX_use_PrivateKey_file(" ... /www.example.com.key") failed
   (SSL: error:0B080074:x509 certificate routines:
    X509_check_private_key:key values mismatch)

da nginx versucht, den geheimen Schlüssel mit dem ersten Zertifikat im Bund anstelle des Serverzertifikats zu verwenden.

Browser speichern in der Regel empfangene Zwischenzertifikate, die von vertrauenswürdigen Zertifizierungsstellen signiert wurden, daher können aktiv genutzte Browser die erforderlichen Zwischenzertifikate bereits besitzen und keine Warnung bezüglich eines Zertifikats anzeigen, das ohne die zugehörige Zertifikatskette gesendet wurde. Um sicherzustellen, dass der Server die vollständige Zertifikatskette sendet, kann das Kommandozeilen-Tool openssl verwendet werden, zum Beispiel:

$ openssl s_client -connect www.godaddy.com:443
...
Certificate chain
 0 s:/C=US/ST=Arizona/L=Scottsdale/1.3.6.1.4.1.311.60.2.1.3=US
     /1.3.6.1.4.1.311.60.2.1.2=AZ/O=GoDaddy.com, Inc
     /OU=MIS Department/CN=www.GoDaddy.com
     /serialNumber=0796928-7/2.5.4.15=V1.0, Clause 5.(b)
   i:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc.
     /OU=http://certificates.godaddy.com/repository
     /CN=Go Daddy Secure Certification Authority
     /serialNumber=07969287
 1 s:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc.
     /OU=http://certificates.godaddy.com/repository
     /CN=Go Daddy Secure Certification Authority
     /serialNumber=07969287
   i:/C=US/O=The Go Daddy Group, Inc.
     /OU=Go Daddy Class 2 Certification Authority
 2 s:/C=US/O=The Go Daddy Group, Inc.
     /OU=Go Daddy Class 2 Certification Authority
   i:/L=ValiCert Validation Network/O=ValiCert, Inc.
     /OU=ValiCert Class 2 Policy Validation Authority
     /CN=http://www.valicert.com//emailAddress=info@valicert.com
...

In diesem Beispiel ist das Subjekt („s“) des Zertifikats Nr. 0 des Servers www.GoDaddy.com vom Aussteller („i“) signiert, der seinerseits das Subjekt des Zertifikats Nr. 1 ist, das vom Aussteller signiert wurde, der wiederum das Subjekt des Zertifikats Nr. 2 ist, das von der allgemein bekannten Zertifizierungsstelle ValiCert, Inc. signiert wurde, deren Zertifikat in der in Browsern integrierten Zertifikatsdatenbank gespeichert ist (die sich in einem dunklen Schrank im Haus befindet, das Jack gebaut hat).

Wenn der Zertifikatsbund nicht hinzugefügt wurde, wird nur das Serverzertifikat Nr. 0 angezeigt.

 

Einheitlicher HTTP/HTTPS-Server

Es kann ein einheitlicher Server konfiguriert werden, der sowohl HTTP- als auch HTTPS-Anfragen bedient:

server {
    listen              80;
    listen              443 ssl;
    server_name         www.example.com;
    ssl_certificate     www.example.com.crt;
    ssl_certificate_key www.example.com.key;
    ...
}

 

Bis Version 0.7.14 konnte SSL nicht selektiv für einzelne lauschende Sockets aktiviert werden, wie oben gezeigt. SSL konnte nur für den gesamten Server mittels der Direktive ssl aktiviert werden, was die Konfiguration eines einheitlichen HTTP/HTTPS-Servers verhinderte. Um dieses Problem zu lösen, wurde der Parameter ssl der Direktive listen hinzugefügt. Daher wird die Verwendung der Direktive ssl in modernen Versionen nicht empfohlen.

 

 

Auswahl des HTTPS-Servers nach Name

Ein typisches Problem tritt bei der Konfiguration von zwei oder mehr HTTPS-Servern auf, die auf derselben IP-Adresse lauschen:

server {
    listen          443 ssl;
    server_name     www.example.com;
    ssl_certificate www.example.com.crt;
    ...
}

server {
    listen          443 ssl;
    server_name     www.example.org;
    ssl_certificate www.example.org.crt;
    ...
}

In dieser Konfiguration erhält der Browser standardmäßig das Serverzertifikat, d. h. www.example.com, unabhängig vom angeforderten Servernamen. Dies liegt am Verhalten des SSL-Protokolls. Die SSL-Verbindung wird hergestellt, bevor der Browser eine HTTP-Anfrage sendet, und nginx kennt den angeforderten Servernamen nicht. Daher kann es nur das Standard-Serverzertifikat anbieten.

Die älteste und zuverlässigste Methode zur Lösung dieses Problems besteht darin, jedem HTTPS-Server eine eigene IP-Adresse zuzuweisen:

server {
    listen          192.168.1.1:443 ssl;
    server_name     www.example.com;
    ssl_certificate www.example.com.crt;
    ...
}

server {
    listen          192.168.1.2:443 ssl;
    server_name     www.example.org;
    ssl_certificate www.example.org.crt;
    ...
}

 

 

SSL-Zertifikat mit mehreren Namen

Es gibt weitere Möglichkeiten, dieselbe IP-Adresse für mehrere HTTPS-Server zu verwenden. Alle diese Methoden haben jedoch ihre Nachteile. Eine solche Möglichkeit ist die Verwendung eines Zertifikats mit mehreren Namen im Feld SubjectAltName des Zertifikats, z. B. www.example.com und www.example.org. Allerdings ist die Länge des Feldes SubjectAltName begrenzt.

Eine andere Methode ist die Verwendung eines Wildcard-Zertifikats, z. B. *.example.org. Ein solches Zertifikat schützt alle Subdomains der angegebenen Domain, jedoch nur auf der angegebenen Ebene. Für dieses Zertifikat eignet sich www.example.org, nicht jedoch example.org und www.sub.example.org. Die beiden oben genannten Methoden können kombiniert werden. Das Zertifikat kann gleichzeitig genaue und Wildcard-Namen im Feld SubjectAltName enthalten, z. B. example.org und *.example.org.

Es ist besser, die Informationen über die Datei des Zertifikats mit mehreren Namen und die Datei mit dem geheimen Schlüssel auf der http-Konfigurationsebene zu platzieren, damit alle Server die einzige Kopie im Speicher erben:

ssl_certificate     common.crt;
ssl_certificate_key common.key;

server {
    listen          443 ssl;
    server_name     www.example.com;
    ...
}

server {
    listen          443 ssl;
    server_name     www.example.org;
    ...
}

Hinweis: Dieser Beitrag kann KI-unterstützt erstellt und anschließend redaktionell geprüft worden sein. Verantwortlich: Dmytro Lomaka, Kaltenkirchen.