[janniweb logo]
Zurück zur Hauptseite

SSL-Zertifikate, CAcert.org und Vertrauen

Jeder verantwortungsbewusste Webserverbetreiber hat sich schon über den Einsatz von HTTP über SSL/TLS Gedanken gemacht (oder zumindest: machen sollen). Wem der Sinn und Zweck von HTTPS-Verbindungen nicht klar ist, der sollte hier vielleicht aufhören zu lesen und sein Dasein als Betreiber einer Webseite überdenken. Nun zum Technischen, quasi eine kleine Einführung.

SSL-Zertifikate enthalten zuerst einmal eine Menge von Informationen, die jeder in seinem Browser in den vorinstallierten Zertifikaten nachlesen kann, von denen ich auf einige eingehen möchte:

Damit kann man zum Beispiel eine Ende-zu-Ende Verschlüsselung über ein asymmetrisches Kryptosystem zwischen Webserver und Browser schaffen, sodass die Daten während der Übertragung für Unbefugte sehr schwer lesbar sind. Das ist genau das, was die meisten wollen (zumindest vermute ich das).

Es gibt im Wesentlichen drei Methoden so ein SSL-Zertifikat zu erzeugen, und dabei muss man sich über ein weiteres Feld des Zertifikats Gedanken machen: den Aussteller. Das ist genau die Stelle, die dafür bürgt, dass das ausgestellte Zertifikat wirklich Ihnen gehört, nämlich die Certificate Authority, kurz CA. Der gemeine Browser erzeugt nicht nur eine verschlüsselte Verbindung mit dem Webserver, sondern überprüft auch dessen Identität mithilfe des Ausstellers: er vertraut allen Zertifikaten bzw. Identitäten, die von einer vertrauten CA ausgestellt wurden. Und woher weiß der Browser, welche CAs vertrauenswürdig sind? Die meisten Browser führen Listen von CAs, denen sie blind vertrauen. Das sind normalerweise Zertifikate von Zertifizierungsstellen, bei denen man für das Ausstellen von Zertifikaten Geld zahlt und sich somit deren Vertrauen erkauft. Zu den großen Stellen gehören z.B. VeriSign, Thawte, RapidSSL und GeoTrust.

Zertifikate erstellen

Der erste Weg: Vertrauen kaufen

Nicht sehr vertrauenswürdig, hm? Dennoch der häufigste Weg. Mit einer einfachen Suche bei der Suchmaschine des Vertrauens findet man im Netz Artikel darüber, dass Leuten von besagten Firmen Zertifikate auf unsinnige Namen registriert haben. Dazu kommen noch weitere Artikel, in denen die Authentifizierungsmethoden genauer beschrieben werden. Kurze Zusammenfassung: lächerlich. Diesen Weg wählen zum Beispiel Banken, große Internet-Auktionshäuser und alle, die mit vielen, sensiblen Kundendaten umgehen. Wie schnell bekommt man da ein Zertifikat, das man gar nicht haben dürfte? Wie leicht lässt sich soetwas missbrauchen? Und wer wacht über die Wächter? Ich will hier gar nicht unterstellen, dass alle Zertifizierungsstellen böse sind oder alle die Identität nur über ominöse Emails bestätigen lassen, dennoch sind auch längst nicht alle vertrauenswürdig, die es besser sein sollten.

Zweiter Weg: das Zertifikat selbst ausstellen

Sehr häufig unter Hobby-Serverbetreibern und Leuten, die ein SSL-Zertifikat haben möchten und nur die Verschlüsselung und nicht die Identitätsprüfung möchten. Bei den self-signed Zertifikaten erstellt man eine eigene CA bzw. ein eigenes CA-Zertifikat und stellt sich dann mithilfe dessen ein Zertifikat für den Webserver aus. Die selbst erstellte CA wird natürlich von keinem Browser erkannt, sodass man so lange eine Sicherheitswarnung bekommt bis man sie entweder dauerhaft akzeptiert oder das CA-Zertifikat in der Vertrauensliste des Browsers unterbringt. Dass man das jedem Webseitenbesucher zumuten möchte, ist wohl nur im kleinen Besucherkreis ratsam, aber das ist eben der Preis. Der CA-Zertifikatsschlüssel kann auch gleichzeitig der „normale“ Zertifikatsschlüssel sein.

Der Mittelweg: Zertifikate von CAcert.org ausstellen lassen

Wer sich ein kostenloses Zertifikat von CAcert.org ausstellen lässt, ist insgesamt etwas besser dran. CAcert.org selbst ist eine australische Organisation, die allein schon von Gesetzeswegen nicht profitorientiert handeln darf, sie verkauft das Vertrauen also nicht. Webmaster legen sich dort einen Account an und müssen dann 100 Assurance-Punkte sammeln. Diese bekommt man, indem man sich von den Assurern, also CAcert.org-Mitgliedern, die schon mindestens 100 Punkte haben, seine Identität bestätigen lässt. Dazu muss der Punktesammler ein Formular ausfüllen und sich dem Assurer gegenüber mit zwei verschiedenen, amtlichen Lichtbildausweisen gegenüber ausweisen. Der Assurer verpflichtet sich dann, das Formular sieben Jahre lang aufzubewahren und kann dann über die Webseite, je nach eigenem Punktestand, 10-35 Punkte vergeben. Besagter Webmaster muss sich dann noch die Domains bestätigen lassen und kann sich dann als vertrauenswürdiges CAcert.org-Mitglied Zertifikate ausstellen lassen. Diese Art der gegenseitigen Prüfung nennt sich Web of Trust und hat das Problem der hierarchischen Struktur mit den Bezahl-CAs nicht; ein Web of Trust lässt sich offenbar wesentlich schwerer missbrauchen. Leider wird zur Zeit noch nicht das CAcert.org CA-Zertifikat in den Vertrauenslisten der gängigen Browser geführt, was aber, hoffentlich, nur noch eine Frage der Zeit ist. Der geneigte Leser kann sich auf der CAcert.org-Seite die passenden Rootzertifikate in seinem Browser installieren. Das ist mit wenigen Klicks getan.

Zur Sache: Zertifikate erstellen

Erstellen des privaten Schlüssels

Der private Schlüssel sollte auch privat bleiben. Kommt er an die Öffentlichkeit, so ist die ganze Identitätsprüfung kompromittiert, also lagert man die Schlüsseldatei am Besten in einem Ordner, auf den nur der Administrator zugreifen kann. Folgendes Beispiel erzeugt einen 2048 Bit großen RSA-Schlüssel und legt ihn in der Datei private.key ab:

	openssl genrsa -out private.key 2048

Mehr als 4096 Bits sind nicht zu empfehlen, da viele ältere Browser das Zertifikat dann für ungültig halten, weil sie nicht auf so große Schlüssel vorbereitet zu sein scheinen. Auch wenn man mehrere Domains hosten möchte, reicht es, eine einzige Schlüsseldatei zu benutzen.

CSR erstellen

Ein Certificate Signing Request enthält Angaben über den Betreiber des Webservers und, besonders wichtig, die URL für die das spätere Zertifikat gelten soll, die man im Common Name (CN)-Feld einträgt. Auch wenn es häufig vorgeschlagen wird, sollte man hier keine Wildcards wie z.B. *.janniweb.de verwenden, weil einige Browser das nicht verstehen. Erst recht dürfen hier nicht mehrere, mit Komma getrennte Domains rein. Hier wird wirklich nur eine einzige Domain eingetragen. Soll das selbe Zertifikat für mehrere Subdomains und/oder TLDs gelten, trägt man diese im SubjAltName-Erweiterungsfeld des Zertifikats ein, wie man in diesem Blog nachlesen kann. Schließlich lautet die Anweisung für den einfacheren Fall:

	openssl req -new -key private.key -out example.com.csr

…und der CSR landet in der Datei example.com.csr. Dieser muss nicht geheim gehalten werden, aber man sollte ihn aufbewahren, falls das Zertifikat irgendwann abläuft und man ein neues erstellen muss.

CSR signieren (lassen)

Um aus einem CSR ein Zertifikat zu erhalten, muss man es signieren lassen. Im zweiten vorgeschlagenen Weg, also bei self-signed-Zertifikaten, signieren wir den CSR selbst. Dieser Schritt wird also ausgelassen wenn wir ein bezahltes Zertifikat oder ein CAcert.org-Zertifikat haben wollen:

	openssl x509 -req -days 365 -signkey private.key -in example.com.csr -out example.com.crt

Bei den beiden anderen Fällen schicken wir unser CSR zu der CA unseres Vertrauens (höhö) oder kopieren es bei CAcert.org in die dafür vorgesehene Maske und wir bekommen das Zertifikat zugeschickt.

Den Webserver einrichten

Gehen wir also davon aus, dass wir den Schlüssel sicher in der Datei /etc/ssl/private/example.key und das Zertifikat in der Datei /etc/ssl/example.com.crt abgelegt haben. Bevor ich zur eigentlichen Konfiguration komme, noch ein Wort zu Server Name Indication (SNI):

Man liest (zu) oft in diversen Foren, dass Leute versuchen, mehrere Domains auf dem selben Server zu hosten, was an sich kein Problem ist. Der Server empfängt die HTTP-Header vom Browser und weiß sofort, welcher VirtualHost dafür zuständig ist. Bei SSL/TLS verhält sich das leider etwas problematischer. SSL ist eine Transportverschlüsselung, d.h. alle Nutzdaten, in dem Fall die HTTP-Header und der eigentliche Rumpf, werden verschlüsselt, bevor sie übertragen werden. Der arme Webserver bekommt also eine Anfrage, dass eine verschlüsselte Verbindung gewünscht wird. Dazu muss dieser dem Client ein Zertifikat anbieten — nur welches? Bisher konnte der Server ja noch gar keine HTTP-Header lesen. In diesem Fall passiert, je nach Webserver, irgendetwas. Das kann heißen, dass der Server dem Client einfach irgendein Zertifikat anbietet oder einfach das erste, was er findet. Angenommen, er sendet das Zertifikat von secure.example.com und wählt dementsprechend den VirtualHost für secure.example.com. Der Client wollte aber eigentlich auf shop.example.com zugreifen und teilt das dem Server über die bekannten HTTP-Header mit. Zu spät. Pech gehabt. Mir sind genau zwei Möglichkeiten bekannt, das Problem zu lösen: jeder mit einem eigenen Zertifikat abgesicherte VirtualHost bekommt eine eigene IP-Adresse. Dann kann der Server noch bevor der SSL-Handshake geschieht, wissen, mit welchem VirtualHost der Client zu kommunizieren wünscht. In Zeiten von IPv4 sind IP-Adressen allerdings oft eine sehr begrenzte Ressource. Die andere Möglichkeit ist eine Erweiterung von SSL, nämlich Server Name Indication. Damit kann dem Server mitgeteilt werden, auf welche Ressource (also welchen VirtualHost) Zugriff gewünscht wird, bevor der Schlüsselaustausch stattfindet. Das erfordert allerdings recht moderne Software, sowohl beim Server (Apache ab 2.2.12, lighttpd ab 1.4.24) als auch beim Client (Internet Explorer 7, Safari ab 3.0, Firefox ab 2.0) und bei beiden OpenSSL ab 0.9.8f. Wenn man eine Webseite betreiben will, die möglichst vielen Benutzern offensteht, ist das natürlich keine Lösung.

Apache

Wer einen Webserver betreibt, sollte ihn auch zu konfigurieren wissen, daher gehe ich nur auf die SSL-spezifischen Teile ein. Nähere Doku dazu findet sich z.B. auf der Projektpage des Apachen. Verschiedene Betriebssysteme und Distributionen legen die Konfiguration von Apache an verschiedenen Stellen ab. Irgendwo gibt es eine Datei, z.B. /etc/apache2/ports.conf, in der man eine Zeile Listen 443 hinzufügt, damit der Apache weiß, dass er auch in Zukunft auf dem HTTPS-Port 443 horchen soll. Dann legt man einen neuen VirtualHost an, der ebenfalls auf Port 443 gebunden ist, mit folgenden Parametern:

	SSLEngine On
	SSLCertificateFile /etc/ssl/example.com.crt
	SSLCertificateKeyFile /etc/ssl/private/example.key

Speichern, mod_ssl aktivieren, Apache neustarten, Schlüssel-Passwort eingeben, fertig.

Lighttpd

Wer lighty verwendet, muss noch den Akt der Vereinigung durchführen: man erwartet von Ihnen, dass Schlüssel und Zertifikat in der selben Datei liegen:

	cp /etc/ssl/private/example.key /etc/ssl/private/example.com.pem
	cat /etc/ssl/example.com.crt >>/etc/ssl/private/example.com.pem

Man kopiert die Dateien einfach zusammen, die Reihenfolge spielt keine Rolle. Dann aktiviert man das SSL-Modul, nimmt sich dessen Konfigurationsdatei zur Brust, bei Debian ist das /etc/lighttpd/conf-enabled/10-ssl.conf und fügt Folgendes hinzu, 1.2.3.4 sei dabei die IP des Servers:

	$SERVER["socket"] == "1.2.3.4:443" {
		ssl.engine = "enable"
		ssl.pemfile = "/etc/ssl/private/example.com.pem"
	}

IPv6-Adressen sind entsprechend der Konvention in eckige Klammern zu setzen, wie z.B. [::1]:443 (hier mit Portangabe). Lighty neustarten (reload reicht hier nicht) und fertig.