seeseekey.net - Invictus Deus Ex Machina

Vor einigen Tagen habe ich damit begonnen alle von mir betriebenen Webseiten auf TLS umzustellen. Dabei nutzte ich Zertifikate der Zertifizierungsstelle Let’s Encrypt. Let’s Encrypt ging dabei im letzten Jahr in Betrieb und liefert kostenlose Zertifikate für TLS. Die CA wird dabei unter anderem von der EFF und Mozilla unterstützt. Im Gegensatz zu anderen Lösungen ist der Prozess bei Let’s Encrypt hochgradig automatisiert, so das die Einrichtung schnell von statten geht.

Der offizielle Client hört dabei auf den Namen Certbot (früher Let’s Encrypt Client) und implementiert das ACME-Protokoll (Automated Certificate Management Environment) über welches der Prozess abgewickelt wird. Neben dem offiziellen Client gibt es viele weitere Clients welche das ACME-Protokoll implementieren. Um Let’s Encrypt unter Ubuntu zu nutzen, muss im ersten Schritt der Client installiert werden:

apt-get install letsencrypt

Nachdem der Client installiert wurde, kann mit der Erzeugung der Zertifikate begonnen werden. Im Gegensatz zu Apache wird unter Nginx die automatische Einrichtung nicht unterstützt. Aus diesem Grund werden nur die Zertifikate mit dem Client erzeugt. Dies geschieht mit dem Befehl:

letsencrypt certonly

Damit wird der interaktive Modus gestartet in welchem das Zertifikat erzeugt werden kann. Zuerst wird nach einer Mailadresse gefragt, mit welcher das Recovery in Notfällen möglich ist. Anschließend müssen die allgemeinen Geschäftsbedingungen akzeptiert werden. Nun wird nach den Domains gefragt, für welche ein Zertifikat erstellt werden soll. Hier kann man mehrere Domains per Komma bzw. Leerzeichen getrennt angeben – allerdings scheint dies in der aktuellen Version nicht zu funktionieren. Stattdessen wird nur für die erste angegebene Domain ein Zertifikat erzeugt. Standardmäßig benötigt Certbot während der Generierung der Zertifikate Zugriff auf den Port 80. Hintergrund für dieses Verhalten ist das der Client kurz einen Webserver aufsetzt um die Kommunikation mit der CA durchzuführen.

Abgelegt werden die erzeugten Zertifikate dabei im Ordner /etc/letsencrypt/. In diesem Ordner liegen neben den Stammzertifikaten auch die eigentlichen Zertifikate für die einzelnen Domains. Nun kann dieses Zertifikat in Nginx eingebunden werden. Dazu muss die Konfigurationsdatei der jeweiligen Seite (z.B. /etc/nginx/sites-available/example) geöffnet werden. Im ersten Schritt wurde dazu in der Konfiguration eine Weiterleitung eingerichtet:

server {
        listen 80;
        listen [::]:80;

        server_name .example.org;

        return 301 https://$host$request_uri$is_args$args;
}

Diese Weiterleitung sorgt dafür das eine Verbindung über unverschlüsseltes HTTP automatisch auf die verschlüsselte Variante umgeleitet wird. Weiter geht es mit der Konfiguration der verschlüsselten Verbindung:

server {
        listen   443 ssl;
        listen [::]:443 ssl;

        ssl_certificate /etc/letsencrypt/live/example.org/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/example.org/privkey.pem;

        ...

Jedes erzeugte Zertifikat von Let’s Encrypt ist 90 Tage lang gültig, so das ein automatischer Prozess eingerichtet werden sollte um die Zertifikate automatisch zu erneuern. Mit dem Befehl:

letsencrypt renew --agree-tos

kann dabei der Erneuerungsprozess angestoßen werden. Möchte man das ganze ohne Risiko testen, so sollte der Parameter –dry-run angefügt werden.

letsencrypt renew --agree-tos --dry-run

Bei der Erneuerung der Zertifikate kann es nun vorkommen das man den Nginx-Server vorher beenden muss. Das ganze kann man in ein Skript gießen:

#!/bin/sh
service nginx stop
letsencrypt renew --agree-tos
service nginx start

Dieses Skript kann man nun zum Beispiel einmal in der Nacht per Cronjob ausführen. Der Client überprüft dabei ob eine Erneuerung notwendig ist und führt diese dann automatisch durch.

Nach der Installation von Gogs läuft dieses standardmäßig über unverschlüsseltes HTTP. Um dies zu ändern muss die app.ini welche sich im Verzeichnis gogs/custom/conf/ befindet bearbeitet werden:

nano app.ini

In der Sektion Server welche für gewöhnlich so aussieht:

[server]
DOMAIN = example.org
HTTP_PORT = 3000
ROOT_URL = http://example.org:300/
DISABLE_SSH = false
SSH_PORT = 22
OFFLINE_MODE = false

müssen einige Änderungen vorgenommen werden. Die Schlüssel PROTOCOL, CERT_FILE und KEY_FILE werden hinzugefügt und die ROOT_URL angepasst. Danach sollte die Server-Sektion in etwa so aussehen:

[server]
DOMAIN = example.org
HTTP_PORT = 3000
PROTOCOL = https
ROOT_URL = https://example.org:300/
CERT_FILE = custom/https/cert.pem
KEY_FILE = custom/https/key.pem
DISABLE_SSH = false
SSH_PORT = 22
OFFLINE_MODE = false

Nachdem die Konfiguration gespeichert wurde muss das passende Zertifikat erzeugt werden:

cd custom
mkdir https
cd https
./gogs cert -ca=true -duration=8760h0m0s -host=example.org

Damit ist Gogs nach einem Neustart des Service per HTTPS und damit verschlüsselt erreichbar.

Beim sogenannten Certificate pinning werden Zertifikate, welche für die Verschlüsselung von Webseiten und anderen Diensten genutzt werden, lokal gespeichert. Dies hat den Vorteil, das dass Zertifikat nicht einfach unbemerkt durch ein anderes Zertifikat ausgetauscht werden kann und erschwert damit das abhören von SSL/TLS-Verbindungen.

Die App konnte im App Store nicht gefunden werden. 🙁

Leider ist diese Funktionalität in den gängigen Browsern nicht vorhanden. Mit dem Firefox-AddOn Certificate Patrol kann man ein solches Certificate pinning im Browser nachrüsten. Zertifikate müssen dabei einmalig akzeptiert werden – anschließend wird man informiert, wenn sich das Zertifikat ändert. Damit ist es für einen Angreifer wesentlich schwieriger geworden, dem Nutzer falsche Zertifikate unterzuschieben.

Wer seine Domains mit Zertifikaten für SSL bzw. TLS ausgerüstet, um den Aufruf per HTTPS zu ermöglichen, fragt sich am Ende wie sinnvoll das ganze konfiguriert ist.

Eine Auswertung für heise.de

Eine Auswertung für heise.de

Mit dem SSL-Test von Qualys kann man das unter ssllabs.com/ssltest/ herausfinden. Nach dem Test erfolgt eine Auswertung, welche mit einer Gesamtnote bewertet wird. Anschließend finden sich in tabellarischer Form die Einzelergebnisse.

Bei einer WordPress Multisite-Installation gibt es unter Updates den Punkt Netzwerk aktualisieren. Wenn man seine Multisite-Installation mit selbstsignierten Zertifikaten betreibt, kann es dabei zu folgender Fehlermeldung kommen:

https://wordpress.example.com/mysite1

Warnung! Problem beim aktualisieren von https://wordpress.example.com/mysite1. Vermutlich gab es einen Zeitablauf. Die Fehlermeldung lautet: SSL certificate problem: self signed certificate

Um das Problem zu lösen packt man folgendes Plugin, in den WordPress-Plugin-Ordner:

<?php
/*
* Plugin Name: Deactivate SSL Verify
* Description: Deactivate SSL verification
* Author: seeseekey
* Author URI: https://seeseekey.net
* Plugin URI: https://seeseekey.net
*/
add_filter('https_ssl_verify', '__return_false');
add_filter('https_local_ssl_verify', '__return_false');

Nachdem das Plugin aktiviert wurde, kann die Aktualisierung des Netzwerkes durchgeführt werden. Anschließend kann das Plugin wieder deaktiviert werden.

Einen Server auf seine SSL-Fähigkeiten zu überprüfen ist für den Laien nicht ohne weiteres möglich. Durch das Bash-Skript testssl.sh sieht dies nun anders aus.

testssl.sh in Aktion

testssl.sh in Aktion

Das freie, unter der GPL2 lizenzierte Skript, dient dazu die Sicherheit der SSL-Implementation eines entfernten Servers zu testen. Die Syntax für den Test ist dabei einfach gehalten:

./testssl.sh example.com

Daneben verfügt “testssl.sh” über weitere Optionen, wie man der Dokumentation entnehmen kann. Dem Autor des Skriptes kann auf Twitter gefolgt werden.

Wenn man mit nicht von einer Certificate Authority signierten Zertifikaten arbeitet, so wird man früher oder später folgende Fehlermeldung unter .NET zu sehen bekommen.

Das Remotezertifikat ist laut Validierungsverfahren ungültig.

Gegeben sei dabei folgendes Beispiel

SmtpClient client=new SmtpClient(host, port);
client.EnableSsl=true;

SSL ist zwar aktiviert, aber das Zertifikat kann in diesem Fall nicht validiert werden. Eine Methode um die Validierung abzuschalten ist dabei folgenden Einzeiler über diese Zeilen zu schreiben:

ServicePointManager.ServerCertificateValidationCallback=delegate { return true; };

Danach bekommt man keine Zertifikatswarnung mehr und kann die Verbindung nutzen.

Für verschlüsselte HTTP Verbindungen benötigt man ein Zertifikat. Dieses kann man sich von einer Zertifizierungsstelle (Certificate Authority, CA) ausstellen lassen. Der Haken an der Sache ist das dies Geld kostet (CACert und StartCom mal außen vor gelassen). Eine Alternative hierzu wäre es das Zertifikat selbst zu erstellen. Bei Diensten die man nur für einen kleinen Nutzerkreis z.B. für die Familie hostet, ist es auch vertretbar die Zertifikatswarnung im Browser über sich ergehen zu lassen. Für die Zertifikate wird ein Ordner erstellt und in diesen gewechselt:

mkdir /etc/nginx/ssl
cd /etc/nginx/ssl

Nun werden das Zertifikat und der Certificate Signing Request erstellt:

openssl genrsa -out example.key 2048
openssl req -new -key example.key -out example.csr

Bei der Erstellung des Certificate Signing Request müssen einige Daten angegeben werden:

Country Name (2 letter code) [AU]:DE
State or Province Name (full name) [Some-State]:Mecklenburg-Vorpommern
Locality Name (eg, city) []:Neubrandenburg 
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Example Inc
Organizational Unit Name (eg, section) []:Skunk works
Common Name (e.g. server FQDN or YOUR name) []:example.org
Email Address []:webmaster@example.org

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

Nun muss das Zertifikat noch signiert werden, bevor wir es verwenden können:

openssl x509 -req -days 730 -in example.csr -signkey example.key -out example.crt

In diesem Fall ist das Zertifikat 730 Tage, also zwei Jahre gültig. Da die Signierung nun abgeschlossen ist, kann das Zertifikat in Nginx eingebunden werden. Dazu öffnen wir die Datei “/etc/nginx/sites-available/example”, wobei “example” hier natürlich für die entsprechende Konfigurationsdatei steht. Dort sollte die SSL Konfiguration vorgenommen werden:

server {
        listen 443 ssl;

        root /var/www/example/root;
        index index.html index.htm;
 
        server_name .example.org;

        ssl_certificate /etc/nginx/ssl/example.crt;
        ssl_certificate_key /etc/nginx/ssl/example.key;
}

Nach dem Aktualisieren der Konfiguration mittels:

service nginx restart

ist die verschlüsselte Verbindung für die eingerichtete Seite aktiv und kann genutzt werden.

Weitere Informationen gibt es unter:
http://nginx.org/en/docs/http/configuring_https_servers.html

Eine eigene ownCloud ist nur die halbe Lösung, wenn man damit Dienste wie Google Mail und Co. ablösen möchte. Was auch gewünscht ist, sind Dinge wie die Synchronisation der Kalender und Kontakte mit dem Mobilgerät. In diesem Fall soll es dabei um iOS gehen, welches in Verbindung mit ownCloud einige Besonderheiten aufweist. Das gleiche gilt auch in Verbindung mit Mac OS X. Bei den Kontakten wird mittels CardDAV synchronisiert. Dies geschieht normalerweise über die URL:

https://example.org/owncloud/remote.php/carddav/addressbooks/seeseekey/contacts

Bei OS X und iOS sieht die URL aber so aus:

example.org/owncloud/remote.php/carddav/principals/seeseekey/

Wichtig ist hierbei das HTTPS oder HTTP weggelasen wird, da dies sonst zu Problemen führt. Der Nutzername “seeseekey” muss dabei durch den eigenen Nutzernamen ersetzt werden. Bei meinem iOS Gerät habe ich die ganze URL nochmal abgewandelt um auf Nummer sicher zu gehen:

example.org:443/owncloud/remote.php/carddav/principals/seeseekey/

Das zeigt dem Gerät welchen Port er für die SSL-Verschlüsselung benutzen soll. Für CalDAV wäre folgende URL zu benutzen:

example.org:443/owncloud/remote.php/caldav/principals/seeseekey/

Unter iOS 7 scheint das ganze in der aktuellen Betaversion noch nicht rund zu laufen, allerdings dauert es bis zur finalen Version noch ein paar Monate, so das man hier Besserung erwarten darf.