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.
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', }, ...}
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
Więcej informacji o tym, jak skonfigurować CORS, znajdziesz w https://enable-cors.org/index.html, a żeby zagłębić się w CORS policy
sprawdź 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.
- 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
- 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
- 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):
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>
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:
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, '&') .replace(/</g, '<') .replace(/>/g, '>') .replace(/"/g, '"')}
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)
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:
- Generuj unikalny token dla każdego żądania użytkownika, tak zwany
CSRF token
. - Przechowuj go bezpiecznie na serwerze i odeślij do użytkownika jako payload odpowiedzi.
- Przechowuj
CSRF token
po stronie klienta. - Gdy użytkownik próbuje wykonać jakiekolwiek żądanie zmieniające stan*, wyślij to
CSRF token
z żądaniem jako ładunek odpowiedzi. - 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
.