Squid und HTTPS – Splice oder Bump? Oder beides? Ein Überblick

Beim Einrichten von squid als transparentem Webproxy auf meiner pfSense bin ich auf ein interessantes Problem gestoßen:

Welche der Einstellungen bei SSL Man-in-the-middle-filtering unter „SSL/MITM Mode“ ist die Beste? Welche ist korrekt? Welche macht Sinn und was ist Quatsch? Und warum überhaupt?

SSL heißt TLS

Zuerst einmal sollte hier etwas auf das Wording geschaut werden: SSL (Secure Socket Layer) gibt’s eigentlich gar nicht mehr, denn es wurde 1999 in TLS (Transport Layer Security) umbenannt. Irgendwie hat sich aber die Bezeichnung SSL bis heute gehalten. Seit 2015 wird allerdings empfohlen, SSLv2 und SSLv3 aus Gründen unsicherer Verschlüsselungstechnologien nicht mehr zu verwenden. TLS liegt mittlerweise in der Version 1.2 vor, 1.3 existiert als Entwurf. Eine Erweiterung, die seit 2003 existiert, ist SNI (Server Name Indicator), die auch für Proxys nicht unrelevant ist.

Server Name Indication (SNI)

Der verschlüsselte Verbindungsaufbau zum Server findet bereits statt, bevor die eigentlich angefragte URL übertragen wird. Da mit dem digitalen Zertifikat die Authentizität einer Website sichergestellt werden soll, muss dieses Zertifikat für genau die eine Website ausgestellt sein. Dies würde allerdings bedeuten, dass für jede Subdomain ein eigenes Zertifikat existieren muss und es keine Möglichkeit gäbe, mehrere Domains unter einer IP-Adresse zu nutzen, was vor Allem bei der Knappheit von IPv4-Adressen ein ernsthaftes Problem darstellt.

Um dies zu umgehen, wurde das SNI-Verfahren eingeführt. Hierbei wird dem Server beim Verbindungsaufbau unverschlüsselt der Parameter server_name übermittelt.

Squid: SslBump Peek and Splice

Nutzt man squid mit der Funktion als SSL-MITM-Proxy, so bekommt man der Konfiguration die Frage gestellt, welchen SSL-MITM-Mode man nutzen möchte: Splice All, Splice Whitelist – Bump All, Benutzerdefiniert. Um sich hier entscheiden zu können, was man wählt muss man wissen, was was bedeutet.

Der Verbindunsgaufbau einer SSL/TLS-Verbindung ist in folgender Grafik dargestellt.

Beim Splicing (zu deutsch so viel wie „spleißen, zusammenkleben“) fungiert der Proxy als TCP-Tunnel und leitet den Verkehr einfach zwischen Client und Server hin und her, für beide Kommunikationspartner existiert der Proxy quasi nicht.

Vorteil: Web-Filtering funktioniert weiterhin super, denn (beispielsweise) squid-guard kann seine URL-Listen problemlos mit der angeforderten URL vergleichen und filtern.

Nachteil: es ist kein Content-Filterng (z.B.mit clamAV) möglich, da die gesamte Übertragung über den Proxy (der ja als Tunnel fungiert) verschlüsselt bleibt.

Beim Bumping entschlüsselt der Proxy die Nachrichten mit einem eigens ausgestellten Zertifikat (die CA des Proxy MUSS auf allen Clients installiert sein) und übernimmt die Kommunikation mit dem Server. Dazu baut er zwei Verbindungen auf: eine zwischen sich und dem Server und eine zwischen sich und dem Client.

Vorteil: Deep packet inspection wird ermöglicht (notwendig für beispielsweise clamAV)

Nachteil: Web-Filtering wird unmöglich.

Ablauf

Der squid ssl_bump ist in drei Schritte aufgeteilt:

  1. Lesen des TCP-Level und der HTTP-CONNECT-Infos
  2. Lesen der TLSClientHello-Nachricht-Infos.
  3. Lesen der TLSServerHello-Nachricht-Infos.

Im ersten Schritt wertet der Proxy die TCP Connect Informationen aus. Ist HTTPS Interception aktiviert, baut der proxy die fake-Verbindung zum angeforderten Ziel auf. Daraufhin werden alle ssl_bump-Regeln (festgelegt in der Datei squid.conf) abgearbeitet. Trifft dort eine zu, wird sie ausgeführt. Die Aktionen, die in den Regeln definiert werden können, sind hier zu finden. Lautet hier die Regel bspw.

ssl_bump splice all

so wird der Proxy als TCP-Tunnel fungieren. Bei peek oder stare wird zu Schritt zwei übergegangen. Beide Konfigurationen für HTTPS MITM in der pfSense führen im ersten Schritt „peek“ aus, was dazu führt, dass im zweiten Schritt die TLSClientHello-Nachricht ausgewertet und wenn möglich der SNI extrahiert wird. An dieser Stelle wird in logs (wie auch in lightsquid) nur Ziel-IP und -port auftauchen, da hier noch kein Domainname verfügbar ist.

In Schritt 3 wird dann die Antwort des Servers (TLSServerHello) ausgewertet, das Zertifikat validiert und wiederum alle Regeln überprüft und die passende ausgeführt. Trifft hier eine Splice-Regel zu, so wird squid wiederum nur als HTTP-Tunnel fungieren, bei Bump übernimmt squid die Kommunikation mit dem Server und dem Client getrennt.

Warum nicht „Splice Whitelist, Bump Otherwise“?

Im Mode „Splice Whitelist, Bump Otherwise“ sollte dem Verständnis nach alles was im Tab ACL unter Whitelist eingetragen wird also „gesplices“ und in einem TCP-Tunnel an den Server geschickt werden, alles andere wird „gebump“ und der Proxy redet mit dem Server. Dies ist allerdings ein Trugschluss, denn alle Einträge in der Whitelist werden intern in der squid.conf folgender Regel zugeordnet:

acl whitelist dstdom_regex -i „var/squid/acl/whitelist.acl“

Der Ausdruck dstdom_regex wie auch dstdomain basieren aber auf HTTP-Informationen, die im gesamten ssl_bump-Prozess noch nicht entschlüsselt sind. Daher wird die regel „Splice Whitelist, Bump otherwise“ dazu führen, das alles gebumpt wird. Das wiederum wird vor allem problematisch bei Anwendungen wie WhatsApp-Web und Threema-Web, die die Herkunft und somit den Aussteller der SSL-Zertifikate überprüfen und bei den fake-Zertifikaten von squid einfach den Verbindungsaufbau beenden.

Will man an dieser Stelle squid bumpen lassen, so kommt der anfangs genannte SNI-Parameter server_name inst Spiel. Hierfür hat squid bei den ACLs (ACL = Access Control List) die Parameter ssl::server_name bzw. ssl::server_name_regex zur Verfügung gestellt. Will man also einzelne splicen, damit sie direkt mit dem Server reden, dann muss man benutzerdefinierte Regeln und ssl_bump-Abläufe definieren. Dazu wählt man beim SSL-MITM-Mode „custom“ (bzw. „benutzerdefiniert“), erweitert unten die benutzerdefinierten Optionen und legt bei „Custom options (before auth)“ die ACLs fest. Für WhatsApp und Threema habe ich folgende Eintragung vorgenommen:


acl noSSLInterception ssl::server_name_regex (w[0-9]+|[a-z]+)\.web\.whatsapp\.com
acl noSSLInterception ssl::server_name_regex .whatsapp\.net
acl noSSLInterception ssl::server_name_regex (w[0-9]+|[a-z]+)\.threema\.ch
acl noSSLInterception ssl::server_name_regex .threema\-forum\.de
acl noSSLInterception ssl::server_name_regex .threema\.ch

Unter „custom options (SSL/MITM)“ muss dann noch festgelegt werden, wie ssl_bump vorgehen soll. Hier wird analog zu „Splice whitelist, bump otherwise“ vorgegagngen, nur statt der whitelist die oben erstellte ACL „noSSLInterception“ angegeben. Das Feld „custom options (SSL/MITM)“ sieht somit folgendermaßen aus:


ssl_bump peek step1
ssl_bump splice noSSLInterception
ssl_bump bump all

Nun noch speichern und squid bumped alles außer WhatsApp und Threema Web. ClamAV scannt jetzt ebenfalls jeglichen HTTPS-Traffic (außer WhatsApp und Threema).

Fazit

Wem SquidGuard als Web-Filter wichtig und vor allem ausreichend ist, der wählt „Splice All“ und wird damit froh und zufrieden. Wer mehr will, der muss sich etwas tiefergehender mit SSL/TLS, HTTPS und squid beschäftigen um sein System so zu konfigurieren, wie er es gern hätte.

Viel Spaß beim Ausprobieren.

Nutzung von pip hinter einem (SSL)-Proxy

Manchmal kann es nicht umgangen werden, dass man seine Verbindung ins Internet über einen Proxy herstellen muss, hier seien als Beispiel Firmennetzwerke genannt. Transparente Proxies stellen kein Problem dar, Proxys mit manueller Konfiguration dagegen doch eher. Da pip nicht die Standard-Proxyeinstellungen des Systems übernimmt, muss man der Paketverwaltung diese manuell mitteilen oder – noch besser – in den Systemeinstellungen hinterlegen.

Manuelle Angabe des Proxy

Hier kommt es jetzt drauf an, ob es sich um einen anonymen Proxy oder einen mit Authentifizierung handelt. Der pip-Aufruf lautet in jedem Fall

pip install <paketname> --proxy <proxyip:port>

Bei Proxy ohne Authentifizierung gibt man einfach die Adresse – wird kein Standardport genutzt zusätzlich den Port – an.

pip install whoosh --proxy http://mein.proxy.com:8080

Bei proxy mit Authentifizierung muss der Nutzername und das Passwort getrennt mit Doppelpunkt und angezeigt durch ein @ der Adresse nach dem Protokoll vorangestellt werden.

pip install whoosh --proxy http://benutzer:passwort@mein.proxy.com:8080

Proxy in den Systemeinstellungen hinterlegen

Wenn der Proxy nicht nur im Ausnahmefall genutzt wird sondern dauerhaft, dann macht es Sinn diesen in den Systemeinstellungen zu hinterlegen.

Linux

Unter Linux nutzt man den „export“-Befehl.

Je nachdem ob es sich um einen http- oder https-proxy handelt:

export http_proxy=http://benutzer:passwort@mein.proxy.com:8080

bzw.

export https_proxy=http://benutzer:passwort@mein.proxy.com:8080

Windows

Unter Windows trägt man die jeweilige Variable in den Systemvariablen ein (System -> Erweiterte Systemeinstellungen -> Umgebungsvariablen).

Nun sollte der Aufruf bei Verbindung über einen Proxy auch ohne die explizite Angabe via –proxy funktionieren.

Vorgehen bei SSL-Fehler

Gibt die Kommandozeile bei Verwendung eines https-Proxy mit MITM-Interception bei der Nutzung von pip eine SSL-Exception zurück, dann muss das Zertifikat von Hand angegeben werden. Dies geschieht durch das Anfügen von –cert an den pip-Befehl.

pip install whoosh --cert <Pfad-zum-Zertifikat>

Es muss der Pfad zu einer .pem-Datei angegeben werden, die das Zertifikat enthält. Zum Erstellen einer solchen gibt’s hier demnächst noch einen Quicktipp.

Der fertige Befehl sieht dann so aus:

pip install --cert ~/certs/thecert.pem

Alternativ kann man den Pfad auch in die pip-Configdatei schreiben, diese liegt unter Linux in ~/.pip/pip.conf und unter Windows in %APPDATA%\pip\pip.ini. Sollte die Datei nicht vorhanden sein, muss sie zuerst erstellt werden (Berechtigungen in Linux nicht vergessen!).

In dieser Datei legt man dann eine section [global] an und trägt dort mit cert = den Wert zur pem-Datei ein.


[global]

cert = /etc/cert/mycert.pem

Jetzt kann pip wie weiter oben beschrieben genutzt werden.