Dlaczego nie ma zasad tego samego pochodzenia dla WebSockets? Dlaczego mogę połączyć się z ws: // localhost?

84

Chciałbym używać WebSockets do komunikacji między procesami dla mojej aplikacji (Daemon <-> WebGUI i Daemon <-> FatClient itp.). Podczas testów próbowałem połączyć się z moim lokalnie działającym serwerem sieciowym (ws: // localhost: 1234) za pośrednictwem klienta JavaScript WebSocket na websocket.org ( http://www.websocket.org/echo.html ).

Moje pytanie brzmi teraz:
dlaczego jest to możliwe? Czy w przeglądarkach nie ma zaimplementowanych zasad dotyczących różnych źródeł (tutaj: FF29 w systemie Linux)?

Pytam, ponieważ gdyby websocket.org był zły, mógłby próbować komunikować się z moim lokalnym serwerem WS i przekierowywać każdą wiadomość, którą otrzymuje z lokalnego hosta na inny serwer:

Lokalny serwer WebSocket Zły serwer sieciowy
pod adresem ws: // localhost: 1234 pod adresem http: //evil.tld
        | | |
        | | ------ [GET /] ---------> |
        | | <----- [HTML + EvilJS] ---- |
        | <------ [connect ws: // ..] ---- | |
        | <---- [trochę komunikacji] -> | |
        | | ---- [zło naprzód] ----> |
        | | |

Nie testowałem całego przypadku użycia, ale połączenie z ws: // localhost z JS dostarczonego przez websocket.org zdecydowanie działa.

binwiederhier
źródło
2
websocket.org nie powinno być złe, gniazda sieciowe mogą być;)
kuldeep.kamboj

Odpowiedzi:

52

Aby odpowiedzieć na pytanie „Dlaczego?” po części powodem, dla którego przeglądarki nie wymuszają tej samej zasady pochodzenia (której CORS jest złagodzeniem) dla WebSockets w przeciwieństwie do wywołań AJAX, jest to, że WebSockets zostały wprowadzone po ustaleniu wartości żądań między źródłami oraz ponieważ nie podlegają SOP na początku, historyczny powód kontroli CORS po stronie klienta nie ma zastosowania.

W przypadku AJAX, w czasach ogólnej Polityki Pojedynczego Źródła, serwery nigdy nie oczekiwały, że uwierzytelniona przeglądarka wyśle ​​żądanie z innej domeny 1 , więc nie musiały zapewniać, że żądanie pochodzi z zaufanej lokalizacji 2 , wystarczy sprawdzić sesyjny plik cookie. Późniejsze zwolnienia, takie jak CORS, musiały mieć kontrole po stronie klienta, aby uniknąć narażania istniejących aplikacji na nadużycia przez naruszenie tego założenia (efektywne wykonanie ataku CSRF ).

Gdyby Internet został wynaleziony dzisiaj, wiedząc, co wiemy teraz, ani SOP, ani CORS nie byłyby wymagane dla AJAX i możliwe jest, że cała weryfikacja pozostałaby serwerowi.

WebSockets, będąc nowszą technologią, zostały zaprojektowane do obsługi scenariuszy międzydomenowych od samego początku. Każdy, kto pisze logikę serwera, powinien być świadomy możliwości wystąpienia żądań między źródłami i przeprowadzać niezbędną weryfikację, bez konieczności stosowania surowych środków ostrożności po stronie przeglądarki a la CORS.


1 To jest uproszczenie. Żądania GET pochodzące z różnych źródeł (w tym znaczniki <img>, <link> i <script>) oraz żądania POST przesyłania formularzy były zawsze dozwolone jako podstawowa funkcja sieci. Obecnie wywołania AJAX między źródłami, których żądania mają te same właściwości, są również dozwolone i nazywane prostymi żądaniami między źródłami . Jednak dostęp do zwróconych danych z takich żądań w kodzie nie jest dozwolony, chyba że jest to wyraźnie dozwolone w nagłówkach CORS serwera. Ponadto to właśnie te „proste” żądania POST są głównym powodem, dla którego tokeny anty-CSRF są niezbędne, aby serwery chroniły się przed złośliwymi witrynami internetowymi.

2 W rzeczywistości bezpieczny sposób sprawdzenia źródła żądania nie był nawet dostępny, ponieważ Referernagłówek można sfałszować, np. Za pomocą luki w zabezpieczeniach otwartego przekierowania. Pokazuje to również, jak słabo rozumiano wówczas luki w zabezpieczeniach CSRF.

staafl
źródło
6
To rzeczywiście odpowiada na pytanie, więc +1. Ale dla porządku, zdecydowanie nie zgadzam się z tym rozumowaniem. Przewiduję, że w wyniku tej decyzji projektowej znaczna liczba witryn korzystających z WebSockets nie zweryfikuje Originnagłówka i w rezultacie wycieknie prywatne dane użytkownika do witryn osób trzecich. Klienci sprawdzający Access-Control-Allow-Originnagłówek, tak jak robią to przed zezwoleniem JS na dostęp do odpowiedzi na jakiekolwiek inne żądanie HTTP z różnych źródeł w sieci, byłoby prostym sposobem na zapobieżenie całej tej klasie ataku (Cross-Site WebSocket Hijacking). Teraz już za późno.
Ajedi32
3
Jestem skłonny się zgodzić, że zmiana projektu zasadniczo przechodzi z podejścia opartego na białej liście do czarnej listy, co jest ryzykowne. Słuszna uwaga.
staafl
43

oberstet odpowiedział na pytanie . Dziękuję Ci! Niestety nie mogę go oznaczyć jako „poprawny”, ponieważ był to komentarz. Przeglądarka wysyła nagłówek „origin”, który może zostać sprawdzony przez aplikację.

W Javie [1]:

@Nadpisanie
public void onOpen (WebSocket clientSocket, ClientHandshake handshake) {
    String clientOrigin = handshake.getFieldValue ("origin");

    if (clientOrigin == null ||! clientOrigin.equals (WEBSOCKET_ALLOWED_ORIGIN_HEADER)) {
        logger.log (Level.WARNING, "Klient nie wysłał poprawnego nagłówka pochodzenia:" + clientOrigin);        

        clientSocket.close ();
        powrót;
    }

    // ...
}

[1] przy użyciu https://github.com/TooTallNate/Java-WebSocket

binwiederhier
źródło
OWASP wspomina sprawdzenie nagłówka Origin (i potencjalnie Referer) w ich ściągawce CSRF jako pierwszy i najważniejszy krok, ale zaleca również pójście o krok dalej i zaimplementowanie specyficznej obrony CSRF. W przypadku WebSockets może to oznaczać dołączenie tokenu zabezpieczającego przed fałszerstwem XSRF do identyfikatora URI WS jako parametru zapytania i weryfikowanie go po stronie serwera po sprawdzeniu pochodzenia.
Kevin Secrist
18

WebSockets mogą komunikować się między domenami i nie są ograniczone przez SOP (Same Origin Policy).

Ten sam problem z zabezpieczeniami, który opisałeś, może wystąpić bez WebSockets.

Zły JS może:

  • Utwórz tag script / image z adresem URL do evil.tld i umieść dane w ciągu zapytania.
  • Utwórz tag formularza, umieść dane w polach i wywołaj akcję „wyślij” formularza, wykonując HTTP POST, który może być międzydomenowy. AJAX jest ograniczony przez SOP, ale zwykły HTTP POST nie. Sprawdź problem z zabezpieczeniami sieci XSRF.

Jeśli coś wstrzykuje javascript na twoją stronę lub otrzymasz złośliwy javascript, twoje zabezpieczenia są już zepsute.

vtortola
źródło
1
Nie martwię się złym JS. Wiem, że to zawsze jest możliwe. To, co mnie naprawdę niepokoi, to przełamanie przeglądarki: każda witryna może teraz komunikować się z lokalnie powiązanym gniazdem WS i wykradać stamtąd dane.
binwiederhier
54
SOP / CORS nie ma zastosowania do protokołu WebSocket, ale przeglądarki wyślą originnagłówek zawierający nazwę hosta serwera, który udostępnił kod HTML z JS, który otworzył połączenie WebSocket. Serwer WebSocket może następnie ograniczyć dostęp, zaznaczając origin.
oberstet
To nie odpowiada na pytanie. Pytanie brzmiało, dlaczego strona internetowa z innej domeny może uzyskać dostęp do lokalnego protokołu WebSocket. W scenariuszu PO nie ma nic, co „wstrzykuje javascript na Twoją stronę” - to jest inny scenariusz. Bez protokołu WebSocket zdalna strona internetowa nie byłaby w stanie odczytać zasobów na hoście lokalnym, ponieważ właśnie temu zapobiega SOP.
sleske