Articles

CORS, XSS i CSRF z przykładami w 10 minut

Ten artykuł powinien być dla Ciebie punktem wyjścia do zapoznania się z istniejącymi standardami bezpieczeństwa w sieci, najczęstszymi atakami internetowymi oraz metodami zapobiegania im. Na końcu dowiesz się również, jak i dlaczego Samy był bohaterem wszystkich (oprócz Ruperta Murdocha, jak sądzę)

Cross-origin resource sharing, lub CORS, jest funkcją bezpieczeństwa IE10+, Chrome 4+, Firefox 3.5+ lub prawie każdej wersji przeglądarki wydanej po 2012 roku z wyjątkiem Opery Mini.

Gdy CORS jest skonfigurowany na serwerze, który jest dostępny w domenie website.com to zasoby z tej domeny, które są żądane przez AJAX muszą być inicjowane z zasobów, które są obsługiwane z tej samej domeny.
CORS

Innymi słowy, jeśli włączymy CORS na domain-b.com i skonfigurujemy go tak, aby zezwalał tylko na GET żądania z domeny domain-b.com to jeśli chcesz użyć obrazu dostępnego pod https://domain-b.com/images/example.png w canvas na swojej stronie, która jest hostowana na domain-a.com, to ten obraz nie zostanie załadowany dla większości odwiedzających.
Twoje zasoby chronione przez CORS będą nadal dostępne, gdy zażąda ich dowolne narzędzie lub przeglądarka, która nie respektuje CORS policy.

Konfiguracja CORS

CORS są domyślnie wyłączone, co oznacza, że nie ma odpowiedniego programu obsługi serwera, który skonfiguruje CORS, co oznacza, że nie możesz uzyskać dostępu do zasobów z różnych źródeł w swoim XHR. Zasadniczo, jeśli nic nie zrobisz lub specjalnie włączysz CORS tylko dla określonych domen, wtedy każde żądanie AJAX próbujące uzyskać dostęp do twoich zasobów zostanie odrzucone, ponieważ przeglądarki internetowe są pełne szacunku dla CORS policy.
To jest powód, dla którego napotykasz problem CORS, gdy zaczynasz rozwijać SPA przy użyciu VueJS i NodeJS. Twoja aplikacja VueJS jest hostowana na http://localhost:8080, a kiedy próbujesz uzyskać dostęp do aplikacji serwera NodeJS na http://localhost:8000, otrzymujesz „No Access-Control-Allow-Origin header is present„, ponieważ są to dwa różne ORIGINS (kombinacja PROTOCOL, HOST i PORT).

Cool fix for CORS issue in VueJS development mode is to set devServer proxy in your vue.config.js file as follows:

module.exports = { ... devServer: { proxy: 'http://localhost:8000', }, ...}
Enter fullscreen mode Exit fullscreen mode

Aby skonfigurować CORS w produkcji powinieneś dodać odpowiedni listener dla żądania OPTIONS. Listener ten powinien wysyłać odpowiedź 200 z no body, ale z Headers, który będzie definiował pożądaną politykę CORS:

Access-Control-Allow-Origin: https://domain-b.comAccess-Control-Allow-Methods: GET
Wejdź w tryb pełnoekranowy Wyjdź z trybu pełnoekranowego

Więcej informacji o tym, jak skonfigurować CORS, znajdziesz w https://enable-cors.org/index.html, a żeby zagłębić się w CORS policysprawdź https://livebook.manning.com/book/cors-in-action/part-1/

XSS

XSS to skrót od Cross Site Scripting i jest to typ ataku typu injection. Jest on wymieniony jako 7 z 10 największych podatności zidentyfikowanych przez OWASP w 2017 roku. Cross site scripting to metoda, w której atakujący wstrzykuje złośliwy skrypt do zaufanej strony internetowej.(sekcja zaktualizowana, dzięki Sandor) Istnieją 3 typy takich ataków.

  1. Stored XSS – Podatność pochodząca z niezabezpieczonych i nie sanityzowanych danych wejściowych użytkownika, które są bezpośrednio przechowywane w bazie danych i wyświetlane innym użytkownikom
  2. Reflected XSS – Podatność pochodząca z niezabezpieczonych i nie sanityzowanych wartości z adresów URL, które są bezpośrednio wykorzystywane na stronach internetowych
  3. DOM based XSS – Podobne jak reflected XSS, niezabezpieczone i nie sanityzowane wartości z adresów URL używanych bezpośrednio na stronach internetowych, z tą różnicą, że DOM based XSS nie przechodzi nawet na stronę serwera

Atak

1. Stored XSS

Tutaj znajduje się przykład ataku. Atakujący wchodzi na Twoją stronę i znajduje niezabezpieczone pole wejściowe, takie jak pole komentarza lub pole nazwy użytkownika i wpisuje złośliwy skrypt zamiast oczekiwanej wartości. Następnie, gdy tylko wartość ta zostanie wyświetlona innym użytkownikom, wykona złośliwy kod. Złośliwy skrypt może próbować uzyskać dostęp do Twojego konta na innych stronach internetowych, może być zaangażowany w atak DDoS lub podobne. Wizualna reprezentacja (źródło geeksforgeeks.org):

XSS example

2. Odbity XSS

Odbity XSS to atak, który ma miejsce, gdy atakujący odkryje stronę z taką luką, na przykład:

oczekiwany URL: https://mywebpage.com/search?q=javascript
złośliwy URL: https://mywebpage.com/search?q=<script>alert('fortunately, this will not work!')</script>

<body>...<div> showing results for keyword <script> document.write(window.location.href.substr(window.location.href.indexOf('q=') + 2))</script></div>......JavaScript results......</body>
Enter fullscreen mode Exit fullscreen mode

Po odkryciu, atakujący przynęca użytkownika do kliknięcia na taki złośliwy URL i voila. Wrażliwe dane użytkownika zostają wykorzystane.

Cykl życia ataku ilustruje przykład dostarczony przez geekforgeeks.com:

Reflected XSS example

3. DOM based XSS

Ten rodzaj ataku jest taki sam jak odbity, ale z tą różnicą, że złośliwa część URL nie będzie w ogóle wysyłana do serwera. Dla powyższego przykładu:

oczekiwany URL: https://mywebpage.com/search?q=javascript
złośliwy URL (reflected XSS): https://mywebpage.com/search?q=<script>alert('fortunately, this will not work!')</script>
złośliwy URL (DOM based XSS): https://mywebpage.com/search#q=<script>alert('fortunately, this will not work!')</script>

Różnica polega na użyciu znaku # zamiast ?. Przeglądarki nie wysyłają części adresu URL po # do serwera, więc przekazują go bezpośrednio do twojego kodu klienta.

Ochrona

Każda wartość, która może być wprowadzona przez użytkownika i jest używana w twojej aplikacji (zarówno po stronie serwera jak i klienta) powinna być traktowana jako niezaufane dane i dlatego powinna być przetwarzana przed użyciem! Powinieneś wykonać kontrolę bezpieczeństwa w swojej aplikacji serwerowej i aplikacji klienckiej, jak również!
Jak pokazano w dokumentacji, VueJS sam ucieka z łańcucha przed uzyskaniem wartości ze zmiennej. Nowsze wersje Angular również niejawnie uciekają od ciągów, więc jeśli używasz Vanilla JS, JQuery lub podobnych, powinieneś zaimplementować ucieczkę ciągów ręcznie.

Istnieją trzy najczęstsze podejścia do przetwarzania niezaufanych danych są wymienione poniżej, a idealna metoda zależy od rzeczywistego typu pola, które musisz przetworzyć.

1. Walidacja ciągów

Weryfikacja jest metodą, w której użytkownik określa zestaw reguł, a żądanie niezaufanych danych do spełnienia tych reguł przed przejściem dalej. Ta metoda jest dobra dla wartości liczbowych, nazwy użytkownika, adresu e-mail, hasła i podobnych pól z konkretnym zestawem reguł składni.

Sprawdź istniejące biblioteki dla twojego frameworka przed rozważeniem napisania własnych walidatorów.

2. String escape

Metoda escape jest przydatna w przypadkach, gdy powinieneś umożliwić użytkownikowi używanie znaków interpunkcyjnych. Metoda ta przechodzi przez ciąg znaków i szuka znaków specjalnych, takich jak < > i zastępuje je odpowiednią nazwą encji znaków HTML. Oto podstawowa funkcja, której możesz użyć:

function escapeText(text) { return text.replace(/&/g, '&amp;') .replace(/</g, '&lt;') .replace(/>/g, '&gt;') .replace(/"/g, '&quot;')}
Enter fullscreen mode Exit fullscreen mode

Ponownie, sprawdź istniejące biblioteki przed napisaniem własnej.

3. Sanityzacja ciągu znaków

Sanityzacja ciągu znaków jest używana, gdy użytkownik może wprowadzić niektóre znaczniki HTML w swoich komentarzach, artykułach lub podobnych. Metoda sanityzacji przechodzi przez tekst i szuka znaczników HTML, które zostały określone przez użytkownika i usuwa je. Jedną z najpopularniejszych bibliotek, która używa tego podejścia jest Google Closure.
Ta metoda jest kosztowna i uważana za szkodliwą, więc wykonaj więcej badań przed jej wyborem.

Przeglądarki internetowe (brak dostępnych źródeł od jakiej wersji, IE naprawił ten problem w 2014r.) automatycznie uciekają z adresów URL przed wysłaniem ich na stronę serwera i udostępniają je w obiekcie window.location również, więc 2 i 3 typ ataku są tutaj tylko po to, aby być ich świadomym i aby wyjaśnić, że parametry URL powinny być również traktowane jako niezaufane dane.

W celu uzyskania bardziej szczegółowych informacji na temat XSS i tego, jak właściwie chronić swoją aplikację, jeśli obracasz dużą ilością niezaufanych danych, sprawdź arkusz OWASP dotyczący zapobiegania XSS.

CSRF

Cross site request forgery lub CSRF jest rodzajem ataku, który występuje, gdy złośliwa strona internetowa, e-mail, blog, wiadomość błyskawiczna lub program powoduje, że przeglądarka użytkownika wykonuje niepożądaną akcję na innej zaufanej stronie, gdzie użytkownik jest uwierzytelniony. Ta luka jest możliwa, gdy przeglądarka automatycznie wysyła zasób autoryzacji, taki jak cookie sesji, adres IP lub podobne z każdym żądaniem.

ATTACK

Załóżmy, że użytkownik jest zalogowany do niezabezpieczonej aplikacji internetowej giełdy i że używasz albo cookie sesji albo JWT cookie do uwierzytelniania. Atakujący również korzysta z Twojej usługi i jest w stanie sprawdzić jak działa Twoje API. Atakujący nakłania użytkownika do wykonania skryptu (poprzez kliknięcie na link SPAM w mailu lub podobny), który wyśle żądanie do Twojego API https://www.stockexchange.com/users/withdraw?how_much=all&address=MY_ADDRESS (okropny projekt API, nie pytaj). Ponieważ żądanie jest wykonywane z przeglądarki, która wysyła ładunek uwierzytelniający z każdym żądaniem, twój serwer internetowy Stockexchange uwierzytelni użytkownika pomyślnie i wykonać transakcję i oszukany użytkownik straci wszystkie swoje saldo, nawet nie wiedząc o tym, ponieważ wszystko działo się w tle. Wizualna reprezentacja (źródło miro.medium.com)
CSRF attack

OCHRONA

Na szczęście istnieją łatwe do wdrożenia wzorce, które zapobiegają tym atakom internetowym. Jednym z najczęściej stosowanych wzorców jest użycie CSRF token. Zasadniczo procedura jest następująca:

  1. Generuj unikalny token dla każdego żądania użytkownika, tak zwany CSRF token.
  2. Przechowuj go bezpiecznie na serwerze i odeślij do użytkownika jako payload odpowiedzi.
  3. Przechowuj CSRF token po stronie klienta.
  4. Gdy użytkownik próbuje wykonać jakiekolwiek żądanie zmieniające stan*, wyślij to CSRF token z żądaniem jako ładunek odpowiedzi.
  5. Przed wykonaniem tego żądania po stronie serwera sprawdź, czy CSRF token jest obecne i czy jest ważne.

Jest to najprostszy sposób zapobiegania atakom CSRF dla wszystkich użytkowników.

Jeśli masz do czynienia tylko z odwiedzającymi, którzy używają nowoczesnych przeglądarek, możesz polegać na atrybucie SameSite pliku cookie sesji.(dzięki Gergely)

Ponieważ odpowiedzi serwera są przetwarzalne w odpowiedzi XHR, nie ma ochrony przed atakiem CSRF, jeśli twoja aplikacja internetowa jest podatna na XSS!

Aby zgłębić temat, sprawdź arkusz OWASP dotyczący CSRF.

BONUS

Krótki film dokumentalny o Samy’m, autorze robaka, który zniszczył MySpace w 2005 roku, wykorzystując lukę XSS i przechodząc obronę MySpace przed CSRF.
https://youtu.be/DtnuaHl378M

Więcej informacji o robaku Samy’ego
https://samy.pl/myspace/tech.html

.