SPDY in Nginx aktivieren

Und gleich noch ein Beitrag zum Thema Nginx: SPDY, eine durch Google initiierte Erweiterung von HTTP bzw. HTTPS, kann bis dato (März 2013) nur durch einen Patch in aktuellen Nginx-Versionen (1.3.x) aktiviert werden.

Da sich Nginx ohne weitere Abhängigkeiten kompilieren lässt, kann man auch auf älteren Linux-Installationen von den Nginx-Features profitieren. So habe ich noch einen etwas betagten Gentoo-Server im Einsatz, auf dem sich nicht mehr zuverlässig mit emerge und dem Portage-Tree arbeiten lässt. Gleiches gilt natürlich auch für eher konservativ eingestellte Enterprise-Distributionen wie SuSE oder RedHat, die entsprechend ihres Auftrags nur sehr veraltete Versionen der Software bereitstellen – wenn überhaupt!

OpenSSL mit NPN installieren

Eine Abhängigkeit ergibt sich aufgrund von SPDY aber doch: OpenSSL muss in der Version ab 1.0.1 vorhanden sein, denn erst in dieser Version wurde das für SPDY erforderliche Next Protocol Negotiation (NPN) implementiert.

Für den aktuellen Verwendungszweck reicht es aus, die Sourcen von OpenSSL herunter zu laden und zu entpacken:

cd /usr/local/src
wget http://www.openssl.org/source/openssl-1.0.1e.tar.gz
tar xzf openssl-1.0.1e.tar.gz

Letztendlich ist es nicht zwingend notwendig, OpenSSL zu kompilieren und zu installieren, schaden kann es aber natürlich nicht. Um Konflikte zu vermeiden, kann ein Installationspfad außerhalb von PATH gewählt werden (standardmäßig ist das Zielverzeichnis /usr/local/ssl):

cd /usr/local/src/openssl-1.0.1e
./config
make
make install

Nginx mit SPDY patchen und installieren

Um SPDY in Nginx nutzen zu können, muss der Source-Code von Nginx heruntergeladen und gepatcht werden. Die README zum SPDY Patch beschreibt das sehr gut. Fürs Kompilieren sind außer dem Pfad zum OpenSSL-Source-Code auch die Optionen --with-http_ssl_module und --with-http_spdy_module anzugeben. Damit sich die Installation in die Linux-Umgebung besser einbettet, habe ich außerdem noch ein paar Pfade angepasst:

cd /usr/local/src
wget http://nginx.org/download/nginx-1.3.13.tar.gz
tar xzf nginx-1.3.13.tar.gz
cd nginx-1.3.13
wget http://nginx.org/patches/spdy/patch.spdy.txt
patch -p1 < patch.spdy.txt
./configure --prefix=/usr/local --with-openssl=/usr/local/src/openssl-1.0.1e --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --with-http_ssl_module --with-http_spdy_module
make
make install

In der nginx.conf muss bei der listen-Direktive ssl und spdy zum Aktivieren angegeben werden:

server {
    listen 443 ssl spdy default_server;

    ssl_certificate      server.crt;
    ssl_certificate_key  server.key;

    ...
}

Verbreitung von SPDY in Browsern

Leider unterstützen noch nicht besonders viele Browser SPDY, zur Zeit sind dies lediglich Google Chrome/Chromium, Firefox und Opera auf den Desktops, bei den mobilen Varianten Android Browser, Opera Mobile, Chrome for Android und Firefox for Android.

Can I use… – für Webentwickler ohnehin zu empfehlen – stellt dazu eine hervorragende Übersicht zur Verfügung: http://caniuse.com/spdy

OCSP Stapling mit Nginx

Mein neuer Lieblings-Webserver Nginx beherrscht ab der Version 1.3.7 zur Geschwindigkeitsoptimierung von HTTPS OCSP Stapling. OCSP Stapling grob erklärt:

Der Browser prüft beim Aufruf von durch SSL/TLS gesicherte Seiten, ob die verwendeten Zertifikate noch gültig sind, also beispielsweise nicht zurückgezogen wurden. Dazu greifen Browser auf die von den Zertifikatherausgebern (Certificate Authorities, CA) bereitgestellten Certificate Revocation Lists (CRL) zu. Dementsprechend erfordert die Prüfung zusätzliche HTTP-Requests und zur Verarbeitung der Liste Rechenleistung des Client-Rechners. CLRs werden je nach CA alle paar Stunden aktualisiert.

Das Online Certificate Status Protocol (OCSP) optimiert dieses System durch eine Verringerung des zur Prüfung notwendigen Datenvolumen und nahezu Echtzeit-Ergebnissen. Nichtsdestotrotz müssen zusätzlichen HTTP-Requests durch den Browser verarbeitet werden, was dementsprechend zu einer höheren Latenz führt. Auch Ausfälle der CA-Server bzw. DoS-Attacken auf ebendiese sind nicht auszuschließen – der Browser kann dann das Zertifikat nicht verifizieren.

OCSP Stapling kann diese Probleme ein stückweit abfedern, indem der Server selbst die OCSP-Anfrage beim CA-Server vornimmt, für eine gewisse Zeit (und für alle Clients) im Zwischenspeicher vorhält und eine signierte Antwort an die Browser zurück gibt.

Konfiguration von OCSP Stapling mit Nginx

Um OCSP Stapling in Nginx zu aktivieren, muss im http– oder server-Kontext – abgesehen von der SSL-Konfiguration – folgende Option aktiviert werden:

ssl_stapling on;

Das alleine wollte aber nicht ausreichen, der Start von Nginx brach mit folgender Fehlermeldung ab:

nginx: [warn] "ssl_stapling" ignored, issuer certificate not found

Erst nachdem ein ssl_stapling_file angeboten wurde, startete Nginx wie erwartet.

OCSP Stapling File erstellen

Leider wird in der Nginx-Dokumentation nicht beschrieben, wie diese Datei zu erstellen ist. Ich habe dann nach etwas googlen eine Anleitung gefunden, mit der ich die Datei nach einigem Herumwerkeln erstellen konnte – auf Anhieb hat es damit auch nicht funktioniert, unter Anderem da das Zertifikat des Servers die gesamte Zertifikatkette beinhalten muss. Später habe ich aber noch einen Blogpost „Priming the OCSP cache in Nginx“ gefunden, der mittels eines kurzen Skripts für mich deutlich besser funktioniert. Daraus ein Gist gebastelt sieht das folgendermaßen aus:

#!/bin/sh
ISSUER_CER=$1
SERVER_CER=$2

URL=$(openssl x509 -in $SERVER_CER -text | grep "OCSP - URI:" | cut -d: -f2,3)

openssl ocsp -noverify -no_nonce -respout ocsp.resp -issuer $ISSUER_CER -cert $SERVER_CER -url $URL

Als erster Parameter wird demzufolge das Zertifikat des Ausstellers und als zweiter Parameter das Server-Zertifikat erwartet. Das Stapling-File bekommt den Namen ocsp.resp und kann anschließend für Nginx abgelegt werden. Die Konfiguration für Nginx sieht anschließend beispielsweise folgendermaßen aus:

ssl_stapling on;
ssl_stapling_file /etc/nginx/ocsp.resp;