WebSocket

Aus besserwiki.de
WebSocket
Websocket connection.png
Ein Diagramm, das eine Verbindung mit WebSocket beschreibt
Internationaler StandardRFC 6455
Entwickelt vonIETF
IndustrieComputerwissenschaft
Typ des AnschlussesTCP
WebsiteOffizielle Website

WebSocket ist ein Computer-Kommunikationsprotokoll, das Vollduplex-Kommunikationskanäle über eine einzige TCP-Verbindung bereitstellt. Das WebSocket-Protokoll wurde von der IETF als RFC 6455 im Jahr 2011 standardisiert. Die aktuelle API-Spezifikation, die es Webanwendungen ermöglicht, dieses Protokoll zu verwenden, ist als WebSockets bekannt. Es handelt sich um einen lebenden Standard, der von der WHATWG gepflegt wird und ein Nachfolger der WebSocket API des W3C ist.

WebSocket unterscheidet sich von HTTP. Beide Protokolle sind auf Schicht 7 des OSI-Modells angesiedelt und hängen von TCP auf Schicht 4 ab. Obwohl sie sich unterscheiden, heißt es in RFC 6455, dass WebSocket "für den Betrieb über die HTTP-Ports 443 und 80 sowie für die Unterstützung von HTTP-Proxys und Vermittlern" konzipiert ist und somit mit HTTP kompatibel ist. Um Kompatibilität zu erreichen, verwendet der WebSocket-Handshake den HTTP-Upgrade-Header, um vom HTTP-Protokoll zum WebSocket-Protokoll zu wechseln.

Das WebSocket-Protokoll ermöglicht die Interaktion zwischen einem Webbrowser (oder einer anderen Client-Anwendung) und einem Webserver mit einem geringeren Overhead als bei Halbduplex-Alternativen wie HTTP-Polling und erleichtert die Datenübertragung in Echtzeit vom und zum Server. Ermöglicht wird dies durch die Bereitstellung eines standardisierten Verfahrens, mit dem der Server Inhalte an den Client senden kann, ohne dass dieser sie vorher anfordert, und durch die Möglichkeit, Nachrichten hin- und herzuleiten, während die Verbindung offen gehalten wird. Auf diese Weise kann eine wechselseitige Unterhaltung zwischen dem Client und dem Server stattfinden. Die Kommunikation erfolgt in der Regel über den TCP-Port 443 (oder 80 bei ungesicherten Verbindungen), was für Umgebungen von Vorteil ist, in denen Internet-Verbindungen, die nicht über das Internet laufen, durch eine Firewall blockiert werden. Ähnliche Zwei-Wege-Kommunikationen zwischen Browser und Server wurden auf nicht standardisierte Weise mit Behelfstechnologien wie Comet oder Adobe Flash Player erreicht.

Die meisten Browser unterstützen das Protokoll, darunter Google Chrome, Firefox, Microsoft Edge, Internet Explorer, Safari und Opera.

Im Gegensatz zu HTTP bietet WebSocket Vollduplex-Kommunikation. Außerdem ermöglicht WebSocket Nachrichtenströme zusätzlich zu TCP. TCP allein befasst sich mit Byteströmen ohne ein inhärentes Konzept für eine Nachricht. Vor WebSocket war eine Vollduplex-Kommunikation über Port 80 mit Comet-Kanälen möglich; die Comet-Implementierung ist jedoch nicht trivial, und aufgrund des TCP-Handshake und des HTTP-Header-Overheads ist sie für kleine Nachrichten ineffizient. Das WebSocket-Protokoll zielt darauf ab, diese Probleme zu lösen, ohne die Sicherheitsvoraussetzungen des Webs zu gefährden.

Die WebSocket-Protokollspezifikation definiert ws (WebSocket) und wss (WebSocket Secure) als zwei neue URI-Schemata (Uniform Resource Identifier), die jeweils für unverschlüsselte und verschlüsselte Verbindungen verwendet werden. Abgesehen vom Namen des Schemas und dem Fragment (d. h. # wird nicht unterstützt) sind die übrigen URI-Komponenten so definiert, dass sie die generische URI-Syntax verwenden.

Mit Hilfe von Browser-Entwicklungstools können Entwickler den WebSocket-Handshake sowie die WebSocket-Frames untersuchen.

Geschichte

WebSocket wurde erstmals als TCPConnection in der HTML5-Spezifikation erwähnt, als Platzhalter für eine TCP-basierte Socket-API. Im Juni 2008 wurde unter der Leitung von Michael Carter eine Reihe von Diskussionen geführt, aus denen die erste Version des Protokolls unter dem Namen WebSocket hervorging.

Der Name "WebSocket" wurde kurz darauf von Ian Hickson und Michael Carter durch die Zusammenarbeit im IRC-Chatraum #whatwg geprägt und anschließend von Ian Hickson für die Aufnahme in die HTML5-Spezifikation verfasst. Im Dezember 2009 war Google Chrome 4 der erste Browser, der den Standard vollständig unterstützte, wobei WebSocket standardmäßig aktiviert war. Die Entwicklung des WebSocket-Protokolls wurde im Februar 2010 von der W3C- und WHATWG-Gruppe zur IETF verlagert und unter der Leitung von Ian Hickson für zwei Überarbeitungen verfasst.

Nachdem das Protokoll ausgeliefert und standardmäßig in mehreren Browsern aktiviert wurde, wurde RFC 6455 unter Ian Fette im Dezember 2011 fertiggestellt.

Mit RFC 7692 wurde eine Komprimierungserweiterung für WebSocket unter Verwendung des DEFLATE-Algorithmus für jede einzelne Nachricht eingeführt.

Browser-Implementierung

Eine sichere Version des WebSocket-Protokolls ist in Firefox 6, Safari 6, Google Chrome 14, Opera 12.10 und Internet Explorer 10 implementiert. Ein detaillierter Protokolltestbericht listet die Konformität dieser Browser mit bestimmten Protokollaspekten auf.

Eine ältere, weniger sichere Version des Protokolls wurde in Opera 11 und Safari 5 sowie in der mobilen Version von Safari in iOS 4.2 implementiert. Der BlackBerry-Browser in OS7 implementiert WebSockets. Aufgrund von Sicherheitslücken wurde es in Firefox 4 und 5 sowie in Opera 11 deaktiviert.

Stand der Implementierung
Protokoll, Version Entwurfsdatum Internet Explorer Firefox (PC) Firefox (Android) Chrome (PC, Mobil) Safari (Mac, iOS) Opera (PC, Mobiltelefon) Android-Browser
hixie-75 4. Februar 2010 4 5.0.0
hixie-76
hybi-00
6. Mai 2010
23. Mai 2010
4.0 (deaktiviert) 6 5.0.1 11.00 (deaktiviert)
hybi-07, v7 April 22, 2011 6
hybi-10, v8 11. Juli 2011 7 7 14
RFC 6455, v13 Dezember, 2011 10 11 11 16 6 12.10 4.4
  • Auf WebKit basierende Browser (z. B. Google Chrome, Apple Safari)
  • Opera, ab Version 10.70
  • Microsoft Edge, ab erster Version
  • Mozilla Firefox, ab Version 4
  • Internet Explorer, ab Version 10.0

JavaScript-Client-Beispiel

// Erzeugt ein neues WebSocket-Objekt mit einer wss-URI als Parameter
const socket = new WebSocket('wss://game.example.com/ws/updates'); <span title="Aus: Englische Wikipedia, Abschnitt &quot;JavaScript client example&quot;" class="plainlinks">[https://en.wikipedia.org/wiki/WebSocket#JavaScript_client_example <span style="color:#dddddd">ⓘ</span>]</span>

// Wird ausgelöst, wenn eine Verbindung mit einem WebSocket geöffnet wird
socket.onopen = function () {
  setInterval(function() {
    if (socket.bufferedAmount == 0)
      socket.send(getUpdateData());
  }, 50);
}; <span title="Aus: Englische Wikipedia, Abschnitt &quot;JavaScript client example&quot;" class="plainlinks">[https://en.wikipedia.org/wiki/WebSocket#JavaScript_client_example <span style="color:#dddddd">ⓘ</span>]</span>

// Wird ausgelöst, wenn Daten über einen WebSocket empfangen werden
socket.onmessage = function(event) {
  handleUpdateData(event.data);
}; <span title="Aus: Englische Wikipedia, Abschnitt &quot;JavaScript client example&quot;" class="plainlinks">[https://en.wikipedia.org/wiki/WebSocket#JavaScript_client_example <span style="color:#dddddd">ⓘ</span>]</span>

// Wird abgefeuert, wenn eine Verbindung mit einem WebSocket geschlossen wird
socket.onclose = function(event) {
  onSocketClose(event);
}; <span title="Aus: Englische Wikipedia, Abschnitt &quot;JavaScript client example&quot;" class="plainlinks">[https://en.wikipedia.org/wiki/WebSocket#JavaScript_client_example <span style="color:#dddddd">ⓘ</span>]</span>

// Wird abgefeuert, wenn eine Verbindung mit einem WebSocket aufgrund eines Fehlers geschlossen wurde
socket.onerror = function(event) {
  onSocketError(event);
};

// callback-Funktion wird gerufen, wenn die Verbindung erfolgreich aufgebaut werden konnte socket.onopen = function () {

   console.log("Verbindung wurde erfolgreich aufgebaut");

};

// callback-Funktion wird gerufen, wenn eine neue Websocket-Nachricht eintrifft socket.onmessage = function (messageEvent) {

   console.log(messageEvent.data);

};

socket.onclose = function (closeEvent) {

   console.log('Die Verbindung wurde geschlossen --- Code: ' + closeEvent.code + ' --- Grund: ' + closeEvent.reason);

}; </syntaxhighlight>

Webserver-Implementierung

Nginx unterstützt WebSockets seit 2013, implementiert in Version 1.3.13, einschließlich der Funktion als Reverse Proxy und Load Balancer für WebSocket-Anwendungen.

Apache HTTP Server unterstützt WebSockets seit Juli 2013, implementiert in Version 2.4.5

Internet Information Services fügte die Unterstützung für WebSockets in Version 8 hinzu, die mit Windows Server 2012 veröffentlicht wurde.

lighttpd unterstützt WebSockets seit 2017, implementiert in Version 1.4.46. lighttpd mod_proxy kann als Reverse Proxy und Load Balancer von WebSocket-Anwendungen fungieren. lighttpd mod_wstunnel kann WebSocket-Tunnel aufbauen, um beliebige Daten, auch im JSON-Format, an eine Backend-Anwendung zu übertragen.

Tempesta FW unterstützt WebSockets für HTTP/1.1 und HTTPS-Verbindungen seit 2022. WebSockets über HTTP/2 nach RFC 8441 wurden von den Entwicklern als nicht weit genug verbreitet angesehen und nicht implementiert.

Protokoll-Handshake

Um eine WebSocket-Verbindung herzustellen, sendet der Client eine WebSocket-Handshake-Anfrage, auf die der Server eine WebSocket-Handshake-Antwort zurücksendet, wie im folgenden Beispiel gezeigt.

Client-Anfrage (genau wie bei HTTP endet jede Zeile mit \r\n und es muss eine zusätzliche Leerzeile am Ende stehen):

GET /chat HTTP/1.1
Rechner: server.beispiel.de
Aktualisierung: Websocket
Verbindung: Upgrade
Sec-WebSocket-Schlüssel: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protokoll: chat, superchat
Sec-WebSocket-Version: 13
Herkunft: http://example.com <span title="Aus: Englische Wikipedia, Abschnitt &quot;Protocol handshake&quot;" class="plainlinks">[https://en.wikipedia.org/wiki/WebSocket#Protocol_handshake <span style="color:#dddddd">ⓘ</span>]</span>

Server-Antwort:

HTTP/1.1 101 Umschalten von Protokollen
Upgrade: Websocket
Verbindung: Aufrüstung
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protokoll: chat <span title="Aus: Englische Wikipedia, Abschnitt &quot;Protocol handshake&quot;" class="plainlinks">[https://en.wikipedia.org/wiki/WebSocket#Protocol_handshake <span style="color:#dddddd">ⓘ</span>]</span>

Der Handshake beginnt mit einer HTTP-Anfrage/Antwort, so dass Server sowohl HTTP-Verbindungen als auch WebSocket-Verbindungen über denselben Port verarbeiten können. Sobald die Verbindung hergestellt ist, wechselt die Kommunikation zu einem bidirektionalen Binärprotokoll, das nicht mit dem HTTP-Protokoll konform ist.

Zusätzlich zu den Upgrade-Headern sendet der Client einen Sec-WebSocket-Key-Header mit base64-kodierten Zufallsbytes, und der Server antwortet mit einem Hash des Schlüssels im Sec-WebSocket-Accept-Header. Dies soll verhindern, dass ein Caching-Proxy eine frühere WebSocket-Konversation erneut sendet, und bietet keine Authentifizierung, keinen Datenschutz und keine Integrität. Die Hashing-Funktion hängt die feste Zeichenfolge 258EAFA5-E914-47DA-95CA-C5AB0DC85B11 (eine UUID) an den Wert aus dem Sec-WebSocket-Key-Header an (der nicht aus base64 dekodiert wird), wendet die SHA-1-Hashing-Funktion an und kodiert das Ergebnis mit base64.

Der RFC6455 verlangt, dass der Schlüssel eine Nonce sein MUSS, die aus einem zufällig ausgewählten 16-Byte-Wert besteht, der base64-kodiert wurde, d. h. 24 Bytes in base64 (wobei die letzten beiden Bytes == sind). Obwohl einige entspannte HTTP-Server kürzere Schlüssel zulassen, weisen viele moderne HTTP-Server die Anfrage mit der Fehlermeldung "ungültiger Sec-WebSocket-Key-Header" zurück.

Sobald die Verbindung hergestellt ist, können Client und Server WebSocket-Daten oder Text-Frames im Vollduplex-Modus hin und her senden. Die Daten sind minimal gerahmt, mit einem kleinen Header gefolgt von der Nutzlast. WebSocket-Übertragungen werden als "Nachrichten" beschrieben, wobei eine einzelne Nachricht optional auf mehrere Datenrahmen aufgeteilt werden kann. Dies kann das Senden von Nachrichten ermöglichen, bei denen die Anfangsdaten verfügbar sind, aber die vollständige Länge der Nachricht unbekannt ist (es wird ein Datenrahmen nach dem anderen gesendet, bis das Ende erreicht und mit dem FIN-Bit bestätigt wird). Mit Erweiterungen des Protokolls kann dies auch zum gleichzeitigen Multiplexen mehrerer Datenströme verwendet werden (z. B. um zu vermeiden, dass ein Socket für eine einzige große Nutzlast monopolisiert wird).

Sicherheitsüberlegungen

Im Gegensatz zu regulären domänenübergreifenden HTTP-Anfragen sind WebSocket-Anfragen nicht durch die Politik des gleichen Ursprungs eingeschränkt. Daher müssen WebSocket-Server den "Origin"-Header während des Verbindungsaufbaus gegen die erwarteten Ursprünge validieren, um seitenübergreifende WebSocket-Hijacking-Angriffe (ähnlich wie Cross-Site Request Forgery) zu verhindern, die möglich sind, wenn die Verbindung mit Cookies oder HTTP-Authentifizierung authentifiziert wird. Es ist besser, Token oder ähnliche Schutzmechanismen zur Authentifizierung der WebSocket-Verbindung zu verwenden, wenn sensible (private) Daten über den WebSocket übertragen werden. Ein aktuelles Beispiel für eine Sicherheitslücke wurde 2020 in Form von Cable Haunt gesehen.

Proxy-Überwindung

Die Client-Implementierungen des WebSocket-Protokolls versuchen zu erkennen, ob der Benutzer-Agent so konfiguriert ist, dass er einen Proxy verwendet, wenn er sich mit dem Ziel-Host und -Port verbindet, und wenn dies der Fall ist, verwendet er die Methode HTTP CONNECT, um einen dauerhaften Tunnel aufzubauen.

Während das WebSocket-Protokoll selbst keine Proxy-Server und Firewalls kennt, verfügt es über einen HTTP-kompatiblen Handshake, so dass HTTP-Server ihre Standard-HTTP- und HTTPS-Ports (80 bzw. 443) mit einem WebSocket-Gateway oder -Server teilen können. Das WebSocket-Protokoll definiert ein ws://- und wss://-Präfix, um eine WebSocket- bzw. eine WebSocket Secure-Verbindung anzuzeigen. Beide Systeme verwenden einen HTTP-Upgrade-Mechanismus, um auf das WebSocket-Protokoll aufzurüsten. Einige Proxy-Server sind transparent und arbeiten problemlos mit WebSocket zusammen; andere verhindern, dass WebSocket korrekt funktioniert, so dass die Verbindung fehlschlägt. In einigen Fällen kann eine zusätzliche Proxy-Server-Konfiguration erforderlich sein, und bestimmte Proxy-Server müssen möglicherweise aufgerüstet werden, um WebSocket zu unterstützen.

Wenn unverschlüsselter WebSocket-Verkehr durch einen expliziten oder transparenten Proxyserver ohne WebSocket-Unterstützung fließt, wird die Verbindung wahrscheinlich fehlschlagen.

Wenn eine verschlüsselte WebSocket-Verbindung verwendet wird, sorgt die Verwendung von Transport Layer Security (TLS) in der WebSocket Secure-Verbindung dafür, dass ein HTTP CONNECT-Befehl ausgegeben wird, wenn der Browser für die Verwendung eines expliziten Proxyservers konfiguriert ist. Dadurch wird ein Tunnel zwischen dem WebSocket Secure Client und dem WebSocket Server aufgebaut, der eine End-to-End-TCP-Kommunikation auf niedriger Ebene über den HTTP-Proxy ermöglicht. Im Falle von transparenten Proxy-Servern weiß der Browser nichts von dem Proxy-Server, so dass kein HTTP CONNECT gesendet wird. Da der Datenverkehr jedoch verschlüsselt ist, können zwischengeschaltete transparente Proxy-Server den verschlüsselten Datenverkehr einfach durchlassen, so dass die Wahrscheinlichkeit, dass die WebSocket-Verbindung erfolgreich ist, bei Verwendung von WebSocket Secure wesentlich größer ist. Die Verwendung von Verschlüsselung kostet zwar Ressourcen, bietet aber oft die höchste Erfolgsquote, da der Datenverkehr durch einen sicheren Tunnel läuft.

In einem Entwurf von Mitte 2010 (Version hixie-76) wurde die Kompatibilität mit Reverse Proxies und Gateways gebrochen, indem acht Byte Schlüsseldaten nach den Headern eingefügt wurden, die jedoch nicht in einem Content-Length: 8-Header angezeigt wurden. Diese Daten wurden nicht von allen zwischengeschalteten Stellen weitergeleitet, was zum Scheitern des Protokolls führen konnte. Neuere Entwürfe (z. B. hybi-09) fügen die Schlüsseldaten in einen Sec-WebSocket-Key-Header ein, wodurch dieses Problem gelöst wird.

Die WebSocket-Protokoll-Spezifikation definiert zwei neue URI-Schemata, ws: für unverschlüsselte, und wss: für verschlüsselte Verbindungen.

Erweiterungen

Die Spezifikation erlaubt die Erweiterung des Websocket-Protokolls durch definierte „Extensions“. Diese werden zwischen Client und Server ausgehandelt. Beispiele: