Gniazdo sieciowe — WebSocket

WebSocket
Połączenie z gniazdem sieciowym.png
Schemat opisujący połączenie za pomocą WebSocket
Międzynarodowy standard RFC  6455
Opracowany przez IETF
Przemysł Informatyka
Typ złącza TCP
Strona internetowa Oficjalna strona internetowa

WebSocket to komputerowy protokół komunikacyjny , zapewniający pełnodupleksowe kanały komunikacyjne za pośrednictwem pojedynczego połączenia TCP . Protokół WebSocket został ustandaryzowany przez IETF jako RFC  6455 w 2011 roku, a interfejs API WebSocket w Web IDL jest standaryzowany przez W3C .

WebSocket różni się od HTTP . Oba protokoły znajdują się w warstwie 7 w modelu OSI i zależą od protokołu TCP w warstwie 4. Chociaż są różne, RFC  6455 stwierdza, że ​​WebSocket „jest przeznaczony do pracy na portach HTTP 443 i 80, a także do obsługi proxy i pośredników HTTP, ", dzięki czemu jest kompatybilny z HTTP. Aby osiągnąć zgodność, uzgadnianie WebSocket używa nagłówka uaktualnienia HTTP do zmiany z protokołu HTTP na protokół WebSocket.

Protokół WebSocket umożliwia interakcję między przeglądarką internetową (lub inną aplikacją kliencką) a serwerem sieciowym przy niższym obciążeniu niż alternatywne rozwiązania półdupleksowe, takie jak odpytywanie HTTP , ułatwiając przesyłanie danych w czasie rzeczywistym zi do serwera. Jest to możliwe dzięki zapewnieniu znormalizowanego sposobu wysyłania przez serwer treści do klienta bez uprzedniego żądania przez klienta i umożliwienia przesyłania komunikatów tam iz powrotem przy zachowaniu otwartego połączenia. W ten sposób między klientem a serwerem może odbywać się dwukierunkowa trwająca konwersacja. Komunikacja odbywa się zwykle przez port TCP o numerze 443 (lub 80 w przypadku połączeń niezabezpieczonych), co jest korzystne w środowiskach, które blokują połączenia z Internetem innym niż WWW za pomocą zapory . Podobną dwukierunkową komunikację przeglądarka-serwer osiągnięto w niestandardowy sposób, wykorzystując technologie tymczasowe, takie jak Comet czy Adobe Flash Player .

Większość przeglądarek obsługuje ten protokół, w tym Google Chrome , Firefox , Microsoft Edge , Internet Explorer , Safari i Opera .

W przeciwieństwie do protokołu HTTP, WebSocket zapewnia komunikację w pełnym dupleksie. Dodatkowo WebSocket umożliwia strumienie wiadomości na wierzchu TCP. Sam protokół TCP obsługuje strumienie bajtów bez wbudowanej koncepcji wiadomości. Przed WebSocket komunikacja na porcie 80 w pełnym dupleksie była osiągalna przy użyciu kanałów Comet ; jednak implementacja Comet nie jest trywialna, a ze względu na uzgadnianie TCP i obciążenie nagłówka HTTP jest nieefektywna w przypadku małych wiadomości. Protokół WebSocket ma na celu rozwiązanie tych problemów bez naruszania założeń bezpieczeństwa sieci.

Specyfikacja protokołu WebSocket definiuje ws(WebSocket) i wss(WebSocket Secure) jako dwa nowe schematy jednolitego identyfikatora zasobów (URI), które są używane odpowiednio do połączeń nieszyfrowanych i szyfrowanych. Oprócz nazwy schematu i fragmentu (tj. #nie jest obsługiwany), pozostałe składniki URI są zdefiniowane do używania ogólnej składni URI .

Korzystając z narzędzi programistycznych przeglądarki, programiści mogą sprawdzać uzgadnianie protokołu WebSocket, a także ramki WebSocket.

Historia

WebSocket został po raz pierwszy wymieniony jako TCPConnection w specyfikacji HTML5 , jako symbol zastępczy dla interfejsu API gniazd opartego na protokole TCP. W czerwcu 2008 roku Michael Carter przeprowadził serię dyskusji , w wyniku których powstała pierwsza wersja protokołu znanego jako WebSocket.

Nazwa „WebSocket” została wymyślona przez Iana Hicksona i Michaela Cartera wkrótce potem dzięki współpracy nad pokojem rozmów #whatwg IRC, a następnie została stworzona do włączenia do specyfikacji HTML5 przez Iana Hicksona. W grudniu 2009 r. Google Chrome 4 była pierwszą przeglądarką, która dostarczała pełną obsługę standardu, z domyślnie włączonym WebSocket. Rozwój protokołu WebSocket został następnie przeniesiony z grupy W3C i WHATWG do IETF w lutym 2010 roku, a autorem dwóch poprawek był Ian Hickson.

Po dostarczeniu protokołu i domyślnie włączonym w wielu przeglądarkach, RFC  6455 został sfinalizowany przez Iana Fette w grudniu 2011 roku.

RFC  7692 wprowadził rozszerzenie kompresji do WebSocket przy użyciu algorytmu DEFLATE na podstawie wiadomości.

Implementacja przeglądarki

Bezpieczna wersja protokołu WebSocket została zaimplementowana w przeglądarkach Firefox 6, Safari 6, Google Chrome 14, Opera 12.10 i Internet Explorer 10. Szczegółowy raport z zestawu testów protokołu zawiera wykaz zgodności tych przeglądarek z określonymi aspektami protokołu.

Starsza, mniej bezpieczna wersja protokołu została zaimplementowana w Operze 11 i Safari 5, a także w mobilnej wersji Safari w iOS 4.2 . Przeglądarka BlackBerry w OS7 implementuje WebSockets. Z powodu luk został wyłączony w Firefoksie 4 i 5 oraz Operze 11.

Stan wdrożenia
Protokół, wersja Data projektu Internet Explorer Firefox (PC) Firefox (Android) Chrome (komputer, telefon komórkowy) Safari (Mac, iOS) Opera (PC, urządzenia mobilne) Przeglądarka Android
hixie-75 4 lutego 2010 4 5.0.0
hixie-76
hybi-00
6 maja 2010
23 maja 2010
4.0 (wyłączone) 6 5.0.1 11.00 (niepełnosprawni)
hybi-07 , v7 22 kwietnia 2011 6
hybi-10 , v8 11 lipca 2011 7 7 14
RFC  6455 , v13 grudzień 2011 10 11 11 16 6 12.10 4.4

Przykład klienta JavaScript

// Creates new WebSocket object with an ws URI as the parameter
const socket = new WebSocket('ws://game.example.com:12010/updates');

// Fired when a connection with a WebSocket is opened,
socket.onopen = function () {
  setInterval(function() {
    if (socket.bufferedAmount == 0)
      socket.send(getUpdateData());
  }, 50);
};

// Fired when data is received through a WebSocket,
socket.onmessage = function(event) {
  handleUpdateData(event.data);
};

// Fired when a connection with a WebSocket is closed,
socket.onclose = function(event) {
  onSocketClose(event);
};

// Fired when a connection with a WebSocket has been closed because of an error,
socket.onerror = function(event) {
  onSocketError(event);
};

Implementacja serwera WWW

Nginx wspiera WebSockets od 2013 roku, zaimplementowany w wersji 1.3.13, w tym działając jako reverse proxy i load balancer aplikacji WebSocket.

Apache HTTP Server obsługuje WebSockets od lipca 2013, zaimplementowany w wersji 2.4.5

Internetowe usługi informacyjne dodały obsługę gniazd WebSockets w wersji 8, która została wydana z systemem Windows Server 2012 .

lighttpd wspiera WebSockets od 2017 roku, zaimplementowany w wersji 1.4.46. lighttpd mod_proxy może działać jako zwrotny serwer proxy i system równoważenia obciążenia aplikacji WebSocket. lighttpd mod_wstunnel może ułatwić tunel WebSocket, umożliwiając klientowi wykorzystanie WebSockets do tunelowania prostszego protokołu, takiego jak JSON , do aplikacji zaplecza.

Uzgadnianie protokołu

Aby nawiązać połączenie WebSocket, klient wysyła żądanie uzgadniania WebSocket, dla którego serwer zwraca odpowiedź uzgadniania WebSocket, jak pokazano w poniższym przykładzie.

Żądanie klienta (tak jak w HTTP , każda linia kończy się \r\ni na końcu musi być dodatkowa pusta linia):

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com

Odpowiedź serwera:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat

Uzgadnianie rozpoczyna się od żądania/odpowiedzi HTTP, dzięki czemu serwery mogą obsługiwać połączenia HTTP, a także połączenia WebSocket na tym samym porcie. Po nawiązaniu połączenia komunikacja przełącza się na dwukierunkowy protokół binarny, który nie jest zgodny z protokołem HTTP.

Oprócz Upgradenagłówków, klient wysyła Sec-WebSocket-Keynagłówek zawierający base64 kodowanego losowych bajtów, a serwer odpowiada z hash klucza w Sec-WebSocket-Acceptnagłówku. Ma to na celu zapobieganie ponownemu wysyłaniu przez serwer proxy pamięci podręcznej poprzedniej konwersacji protokołu WebSocket i nie zapewnia uwierzytelniania, prywatności ani integralności. Funkcja mieszająca dołącza stały ciąg ( uUID ) do wartości z nagłówka (który nie jest dekodowany z base64), stosuje funkcję mieszającą SHA-1 i koduje wynik przy użyciu base64. 258EAFA5-E914-47DA-95CA-C5AB0DC85B11Sec-WebSocket-Key

RFC6455 wymaga, aby klucz MUSI był jednorazowy składający się z losowo wybranej 16-bajtowej wartości zakodowanej w base64, czyli 24 bajtów w base64 (przy czym ostatnie dwa bajty to ==). Chociaż niektóre zrelaksowane serwery HTTP pozwalają na prezentację krótszych kluczy, wiele nowoczesnych serwerów HTTP odrzuci żądanie z błędem „nieprawidłowy nagłówek Sec-WebSocket-Key”.

Po nawiązaniu połączenia klient i serwer mogą przesyłać dane lub ramki tekstowe protokołu WebSocket tam iz powrotem w trybie pełnego dupleksu . Dane są w minimalnych ramkach, z małym nagłówkiem, po którym następuje ładunek . Transmisje WebSocket są opisywane jako „wiadomości”, w których pojedyncza wiadomość może być opcjonalnie podzielona na kilka ramek danych. Może to pozwolić na wysyłanie wiadomości, w których dane początkowe są dostępne, ale pełna długość wiadomości jest nieznana (wysyła jedną ramkę danych za drugą, aż do osiągnięcia końca i zatwierdzenia bitem FIN). Dzięki rozszerzeniom protokołu można to również wykorzystać do multipleksowania kilku strumieni jednocześnie (na przykład w celu uniknięcia monopolizowania użycia gniazda dla pojedynczego dużego ładunku).

Względy bezpieczeństwa

W przeciwieństwie do zwykłych międzydomenowych żądań HTTP żądania WebSocket nie są ograniczone przez zasady tego samego pochodzenia . Dlatego serwery WebSocket muszą zweryfikować nagłówek „Origin” pod kątem oczekiwanych źródeł podczas nawiązywania połączenia, aby uniknąć ataków Cross-Site WebSocket Hijacking (podobnych do Cross-site request forgery ), które mogą być możliwe, gdy połączenie jest uwierzytelniane za pomocą plików cookie lub uwierzytelniania HTTP . Lepiej jest używać tokenów lub podobnych mechanizmów ochrony do uwierzytelniania połączenia WebSocket, gdy wrażliwe (prywatne) dane są przesyłane przez WebSocket. Żywy przykład podatności zaobserwowano w 2020 r. w postaci Cable Haunt .

Przechodzenie przez proxy

Implementacje klienta protokołu WebSocket próbują wykryć, czy agent użytkownika jest skonfigurowany do korzystania z serwera proxy podczas łączenia się z hostem docelowym i portem, a jeśli tak, używa metody HTTP CONNECT do skonfigurowania trwałego tunelu.

Chociaż sam protokół WebSocket nie jest świadomy istnienia serwerów proxy i zapór ogniowych, posiada funkcję uzgadniania kompatybilną z HTTP, dzięki czemu serwery HTTP mogą udostępniać swoje domyślne porty HTTP i HTTPS (odpowiednio 80 i 443) z bramą lub serwerem WebSocket. Protokół WebSocket definiuje prefiks ws:// i wss://, aby wskazać odpowiednio połączenie WebSocket i WebSocket Secure. Oba schematy używają mechanizmu uaktualniania HTTP w celu uaktualnienia do protokołu WebSocket. Niektóre serwery proxy są przezroczyste i działają dobrze z WebSocket; inne uniemożliwią prawidłowe działanie WebSocket, powodując awarię połączenia. W niektórych przypadkach może być wymagana dodatkowa konfiguracja serwera proxy, a niektóre serwery proxy mogą wymagać uaktualnienia do obsługi protokołu WebSocket.

Jeśli niezaszyfrowany ruch protokołu WebSocket przepływa przez jawny lub przezroczysty serwer proxy bez obsługi protokołu WebSocket, połączenie prawdopodobnie zakończy się niepowodzeniem.

Jeśli używane jest szyfrowane połączenie WebSocket, użycie Transport Layer Security (TLS) w połączeniu WebSocket Secure gwarantuje, że polecenie HTTP CONNECT zostanie wydane, gdy przeglądarka jest skonfigurowana do korzystania z jawnego serwera proxy. Powoduje to utworzenie tunelu, który zapewnia niskopoziomową komunikację TCP typu end-to-end przez proxy HTTP, między klientem WebSocket Secure a serwerem WebSocket. W przypadku przezroczystych serwerów proxy przeglądarka nie zna serwera proxy, więc nie jest wysyłane połączenie HTTP CONNECT. Ponieważ jednak ruch przewodowy jest szyfrowany, pośrednie przezroczyste serwery proxy mogą po prostu przepuszczać zaszyfrowany ruch, więc istnieje znacznie większa szansa, że ​​połączenie WebSocket powiedzie się, jeśli zostanie użyty protokół WebSocket Secure. Korzystanie z szyfrowania nie jest wolne od kosztów zasobów, ale często zapewnia najwyższy wskaźnik sukcesu, ponieważ byłoby to podróżowanie przez bezpieczny tunel.

Wersja robocza z połowy 2010 r. (wersja hixie-76) złamała kompatybilność z odwrotnymi serwerami proxy i bramami, umieszczając osiem bajtów kluczowych danych po nagłówkach, ale nie reklamując tych danych w Content-Length: 8nagłówku. Te dane nie zostały przesłane przez wszystkie półprodukty, co mogło prowadzić do niepowodzenia protokołu. Nowsze wersje robocze (np. hybi-09) umieszczają kluczowe dane w Sec-WebSocket-Keynagłówku, rozwiązując ten problem.

Zobacz też

Uwagi

Bibliografia

Zewnętrzne linki