WireGuard

From
Revision as of 15:35, 15 October 2018 by SaschaT (talk | contribs) (Created page with "WireGuard ist eine relativ neue, vollständig im Kernel Space implementierte VPN-Lösung. Sie wurde als Ersatz insbsondere für IPsec, aber auch für User-Space-Lösungen wie...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

WireGuard ist eine relativ neue, vollständig im Kernel Space implementierte VPN-Lösung. Sie wurde als Ersatz insbsondere für IPsec, aber auch für User-Space-Lösungen wie OpenVPN entwickelt.

Motivation

Bisherige VPN-Lösungen sind i.d.R. sehr komplex. Laut Angaben des Entwicklers kommt die IPsec-Implementierung StrongSwan auf ca. 420.0000 LOC und OpenVPN auf ca. 120.000 LOC, während WireGuard mit weniger als 4.000 auskommt. Zudem gibt es für bisherige Lösungen i.d.R. viele Konfigurationsmöglichkeiten, eine sichere IPsec-Konfiguration zu erstellen, wird oft als schwieriger und langwieriger Prozess angesehen. WireGuard hingegen verzichtet auf jede Konfigurierbarkeit der kryptographischen Komponenten, die Konfigurationsmöglichkeiten beschränken sich auf das nötigste. Durch die Kompaktheit des Codes, die durch diese Einschränkungen möglich wird, versprechen sich die Entwickler eine vergleichsweise einfache Überprüfbarkeit.

Umsetzung

Grundlegendes

Um die Versprechen: Schnelligkeit, Sicherheit und Einfachheit zu realisieren wurden beim Design von WireGuard moderne kryptografische Prinzipien gewählt und auf eine übersichtliche Implementierung als Kernelmodul für Linux geachtet. Alle Daten werden grundsätzlich verschlüsselt und unter Gewährleistung von Perfect Forward Secrecy (PFS) übertragen. Auch eine Verschleierung der Identitäten der Netzwerkteilnehmer soll vom Protokoll gegenüber Dritten erreicht werden. Optional können die Peers (über einen beliebigen sicheren Kanal) symmetrische Schlüssel austauschen, um einen leichten Post Quantum Cryptography Schutz zu erreichen. Die Implementierung von WireGuard bietet ein Interface der Schicht 3 des ISO/OSI Schichtenmodells für Netzwerkprotokolle. Ein Service zum initialen Austausch öffentlicher Schlüssel wird daher von WireGuard nicht angeboten. Innerhalb der Schicht wird die Einhaltung einer Schichtenarchitektur jedoch zugunsten einer einfacheren Implementierbarkeit aufgegeben. Nutzer können WireGuard über eine transparente virtuelle Netzwerkschnittstelle verwenden, die mit Standardtools der Netzwerkadministration wie iptables angepasst werden kann. Die Identitäten aller Netzwerkteilnehmer sind dabei eindeutig an ihre öffentlichen Schlüssel geknüpft, welche vor der Konfiguration zwischen den Teilnehmern ausgetauscht werden müssen. Neben der Verwendung moderner kryptografischer Prinzipien stützt sich das Sicherheitskonzept von WireGuard auf ein methodisches Design, bei dem der Versuch unternommen wird, die Komplexität von WireGuard so gering wie möglich zu halten, typische Schwachstellen wie dynamische Speicherallokation zu vermeiden und Vorkehrungen gegen gängige Angriffe zu treffen. Zu diesen Vorkehrungen zählen Zeitstempel in Handshake Nachrichten (Replay-Angriffe) und ein Crypro-Cookie Mechanismus (CPU-Exhaustion Angriff), ein optionaler Teil des Handshakes.

Verwendete kryptografische Funktionen

WireGuard verzichtet auf so genannte "cipher agility" und beschränkt sich daher auf drei kryptografische Grundfunktionen. Symmetrische Verschlüsselung erfolgt mittels ChaCha20Poly1305 im Authenticated Encryption with Associated Data (AEAD) Modus. Verschlüsselte Daten werden also grundsätzlich auf Integrität geprüft und authentifiziert. Der Schlüsselaustausch im Handshake erfolgt in Form eines Elliptic Curve Diffie-Hellman (ECDH) Schlüsselaustauschs mittels Curve25519. Als universelle Hashfunktion wird BLAKE2s eingesetzt. Diese wird für die Generierung von Message Authentication Codes (MAC) , Keyed-Hash Message Authentication Codes (HMAC) und die Schlüsselableitung über HMAC-based Key Derivation Funciton (HKDF) eingesetzt. Die Verwendung der Linux Kernel Crypto API wurde zugunsten einer eigenen Implementierung der kryptografischen Primitiven aufgegeben.

Protokoll

Das von WireGuard verwendete Protokoll wurde auf Basis des Noise Protocol Framework entworfen und zeichnet sich durch die Verwendung statischer Header fester Länge aus, was eine abwärtskompatible Erweiterung erschwert. Es nutzt einen 1-RTT Handshake und implementiert einen Krypto-Cookie Mechanismus. Das Design basiert auf einem Zustandsautomaten, über den das Protokoll formal verifiziert wurde.

Insgesamt versendet WireGuard vier verschiedene Nachrichtentypen, die zwischen zwei Peers ausgetauscht werden können. Dabei entfallen drei der Nachrichtentypen in den Bereich des Handshakes. Der Verbindungsaufbau und Schlüsselaustausch kann von beiden Seiten mittels der die Initiate Handshake Message, angestoßen werden. Der Sender der Initiate Handshake Message wird im weiteren als Initiator und Ihr Empfänger als Responder bezeichnet. Nach Erhalt sendet der Responder im Normalfall eine Handshake Response Message. Anschließend kann der Initiator Transport Messages an den Responder schicken, um Nutzdaten zu übertragen. Eine Sitzung ist höchstens 180 Sekunden oder für Versand von rund 2^64 Nachrichten gültig, danach muss der Handshake wiederholt werden. Dies dient dem Erhalt von PFS und vermeidet einen unsicheren Betrieb der verwendeten Stromchiffre zur symmetrischen Verschlüsselung der Nachrichten. Sollte der Responder zum Empfangszeitpunkt unter Überlast leiden, wird ein Crypto-Cookie generiert und eine Cookie Reply Message anstelle einer Handshake Response Message versendet. Der Cookie kann vom Initiator für einen begrenzten Zeitraum genutzt werden, um künftige Handshake Messages mit einer schwachen Authentifizierung zu versenden. Dadurch können unnötige, "teuere" ECDH Berechnung vermieden werden. Mittels des Cookie Mechanismus werden CPU-exhaustion Angriffe vermieden und ist so entworfen, dass er nicht seinerseits genutzt werden kann, um den Initiator mittels eines DOS anzugreifen. Ein Man-In-The-Middle (MITM) mit Kenntnis der öffentlichen Schlüssel der kommunizierenden Peers kann diesen Schutz zwar überwinden, wäre allerdings ohnehin in der Lage einen Denial of Service (DOS) Angriff durchzuführen.


Installation und Konfiguration

WireGuard ist als Paket für die meisten Linux-Distributionen verfügbar, alternativ kann es natürlich auch selbst kompiliert werden. Die Wireguard-Pakete bestehen i.d.R. aus einem Paket mit Userspace Utilities zur einfachen Konfiguration (wg und wg-quick) sowie aus dem Kernelmodul.

Soll WireGuard als VPN-Server verwendet werden, der Clients die Mitnutzung seiner Internetverbindung ermöglicht, muss nach der Installation zunächst IP-Forwarding im Kernel aktiviert werden. Hierzu wird folgende Zeile in der Datei /etc/sysctl.d/99-sysctl.conf auskommentiert oder ergänzt:

net.ipv4.ip_forward = 1

Die WireGuard-Konfigurationsdatei auf dem Server (z.B. /etc/wireguard/wg0.conf für ein Interface wg0) folgt dem folgenden Schema:

[Interface]
PrivateKey = <hier private key des Servers einfügen>
ListenPort = 5555
Address = 10.0.0.1/24
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o enp0s3 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o enp0s3 -j MASQUERADE

[Peer]
PublicKey = <hier public key des ersten Clients einfügen>
AllowedIPs = 10.0.0.2/32

Dabei ist Address im Abschnitt Interface die VPN-IP-Adresse des Servers, die iptables-Befehle in PostUp und PostDown werden automatisch ausgeführt, um das korrekte Forwarding der Pakete an die Clients zu ermöglichen. AllowedIPs im Abschnitt Peers ist die VPN-IP-Adresse des Peers. Für weitere Clients können weitere Peer-Abschnitte hinzugefügt werden.

Die Konfiguration eines Clients könnte wie folgt aussehen:

[Interface]
PrivateKey = <hier Private Key des Clients einfügen>
ListenPort = 5555
Address = 10.0.0.2/24

[Peer]
PublicKey = <hier Public Key des Servers einfügen>
AllowedIPs = 0.0.0.0/0, ::0/0
Endpoint = 192.168.56.101:5555
PersistentKeepalive = 25

Hier agiert der Server als Peer. Der Endpoint ist die öffentliche IP und der Port des Servers und für den Verbindungsaufbau notwendig. AllowedIPs definiert, auf welche IP-Adressen der Client über den Server zugreifen möchte, hier können z.B. lokale und Netzwerk-IPs ausgeschlossen werden. 0.0.0.0/0 bedeutet, dass alle IPs über den Server zugegriffen werden sollen. Mit PersistentKeepalive kann eine kontinuierliche Kommunikation auch ohne Netzwerkverkehr erzwungen werden, dies ist v.a. für Clients hinter einem NAT notwendig. Als weitere Option kann im Interface-Bereich ein zu verwendender DNS-Server festgelegt werden.

Alternativ kann WireGuard auch über die interfaces-Datei oder systemd konfiguriert werden.

WireGuard kann dann über den folgenden Befehl gestartet werden, dabei wird das Interface automatisch erzeugt:

systemctl start wg-quick@wg0

Unterstützte Betriebssysteme

Derzeit werden GNU/Linux, macOS, FreeBSD, OpenBSD, OpenWRT und Android unterstützt. An einer Userspace-Implementierung, die dann auch auf Windows funktionieren soll, wird nach Aussage der Entwickler derzeit gearbeitet.

Es ist bereits eine proprietäre Closed Source Windows-Implementierung mit dem Namen "TunSafe" von einem anderen Entwickler verfügbar, die auf dem TUN/TAP-Treiber von OpenVPN basiert. Der WireGuard-Hauptentwickler Donenfeld rät von der Verwendung dieser Implementation explizit ab.

Usability

Die Clients benötigen für die Verbindung mit einem WireGuard-Server eine Konfigurationsdatei, die unter anderem ihren Private Key und den Public Key des Servers enthält. Aus Sicherheitsgründen ist es natürlich empfehlenswert, den Private Key auf dem Client zu generieren, allerdings muss der Nutzer dann die Konfigurationsdatei selbst erstellen. Dies erfordert zumindest Grundkenntnisse über die darin vorhandenen Parameter.

Letztendlich werden viele Serverbetreiber wohl die Konfigurationsdateien selbst generieren und den Clients zur Verfügung stellen, damit dieser Schritt entfällt. Für den Andoid-Client kann zudem ein QR-Code mit der Konfiguration erstellt werden.

Mit dem folgenden Skipt wgmanage.sh, das auf dem Server ausgeführt werden kann, lassen sich automatisiert Client-Konfigurationen und QR-Codes erzeugen und direkt zur Server-Konfiguration hinzfügen, sodass die Clients sich sofort verbinden können.

#!/bin/bash
SERVER_PUBLIC_KEY="PASTE PUBLIC KEY HERE"
SERVER_PUBLIC_IP="192.168.56.101"
SERVER_PORT="5555"
CLIENT_SUBNET="24"
# end of config

CLIENT_PRIVATE=`wg genkey`
CLIENT_PUBLIC=`echo "$CLIENT_PRIVATE" | wg pubkey`
if [ $# -lt 2 ] || (([ $# -lt 3 ] && [ $1 == "-a" ]) || ([ $1 != "-a" ] && [ $1 != "-r" ])); then
        echo "Usage (add client): wgmanage -a CLIENT_IP CLIENT_OUTFILE [QR_OUTFILE]"
        echo "Usage (remove client): wgmanage -r CLIENT_IP"
        exit
fi
if [ $1 == "-a" ]; then
        echo -e "[Interface]\nAddress = $2/$CLIENT_SUBNET\nPrivateKey = $CLIENT_PRIVATE\n\n[Peer]\nPublicKey = $SERVER_PUBLIC_KEY\nAllowedIPs = 0.0.0.0/0, ::0/0\nEndpoint = $SERVER_PUBLIC_IP:$SERVER_PORT" > $3
        echo -e "\n[Peer]\nPublicKey = $CLIENT_PUBLIC\nAllowedIPs = $2/32" >> /etc/wireguard/wg0.conf
        systemctl restart wg-quick@wg0
        if [ $# -ge 4 ]; then
                qrencode -o $4 < $3
        fi
        exit
fi
if [ $1 == "-r" ]; then
        echo "Not implemented yet"
fi

Das Skript kann aufgerufen werden mit:

Client hinzufügen und QR-Code im Terminal anzeigen: ./wgmanage.sh -a [Client-IP] [Konfiguratiosdatei] Client hinzufügen und QR-Code als png speichern: ./wgmanage.sh -a [Client-IP] [Konfigurationsdatei] [QR-Datei]

Das Skript kann bei Bedarf natürlich auch so erweitert werden, dass Clients auch aus der WireGuard-Serverkonfiguration entfernt werden können. Diese Funktion ist bereits im Skript vorgesehen, aber noch nicht implementiert.


Quellen