Nie tak dawno pojawiły się alarmujące wieści o dziurach w mBank. Wieści, choć prawdziwe (dziura była), były nieco przesadzone, a i sama podatność wcale nie tak prosta do wykorzystania, jak było to przedstawiane. W ramach "odprysków" tej sprawy stałem się uczestnikiem dość ciekawej dyskusji. O niej słów kilka.
O NIE cross-site scripting słów kilka
U podstawy dyskusji pojawił się następujący przykład:
- Zaloguj się do bankowości internetowej,
- W innym oknie przeglądarki wklej jakiś znany URL z serwisu
- ...o jejku jejku, otwarła się strona...
I co z tego? A dlaczego miała by się nie otworzyć (pominę tutaj możliwość zabezpieczenia przez weryfikację Refer, bo to akurat mało istotne dla całej sprawy jest). I wcale nie jest dziwne, że w oknie tym widać dane zalogowanego użytkownika. Dla serwera nie ma najmniejszego znaczenia z jakiego okna przeglądarki klient się łączy, ważne, by był podany prawidłowy identyfikator (bądź identyfikatory) sesji.
Tu od razu ciekawostka - przeglądarki z tabami są ZŁE! A dlaczego? O tym kiedy indziej.
Przykładem praktycznego wykorzystania tej sytuacji miał być poniższy kod:
var x = new ActiveXObject("Msxml2.XMLHTTP"); x.onReadyStateChange = status; x.open("GET","tu jakis url",true); x.send(null); function status() { if(x.readyState==4) { var re=new RegExp("CCardNbr=([0-9]+)"); var m=re.exec(x.responseText); if(m!=null) { alert("TWOJA KARTA KREDYTOWA TO " + m[1]); } } }
Po otwarciu strony zawierającej ten kod, użytkownik miał zobaczyć numer swojej karty kredytowej, o ile oczywiście był zalogowany do bankowości internetowej. To nawet działa w niektórych przypadkach, ale przedstawiony scenariusz ataku miał mniejsze szanse na sukces, niż ja na 5 000 000 w najbliższym losowaniu LOTTO.
Najpierw jak działa powyższy fragment:
- tworzony jest obiekt XMLHttpRequest,
- za jego pośrednictwem otwierany jest wskazany link w bankowości elektronicznej,
- w wynikach zwróconych przez zapytanie wyszukiwany jest numer karty kredytowej,
- numer karty jest prezentowany przerażonemu użytkownikowi (...a może być wysłany w świat...)
Przerażające? Strasznie... Dlaczego to działa? Obiekt XMLHTTPRequest stworzony jest w przeglądarce, jeśli w tej chwili użytkownik jest zalogowany do jakiegoś serwisu, to po stronie klienta jest najprawdopodobniej ustawione ciasteczko z identyfikatorem tej sesji. Przeglądarka bardzo usłużnie wyśle to ciasteczko razem z zapytaniem wygenerowanym do tego serwisu przez XMLHTTPRequest, a skoro sesja jest prawidłowa, to i serwis zwróci oczekiwany wynik. Też nic niespotykanego... A przerażenie rośnie.
To teraz scenariusz atakuSpreparowanie odpowiedniej strony i rozpropagowanie linku do niej, rozesłanie przez komunikatory internetowe, rozesłanie maili, ktoś kiedyś kliknie i być może jednocześnie będzie zalogowany a ZŁE MOCE wejdą w posiadanie ich numeru karty kredytowej. Wszyscy już zlikwidowali swoje rachunki w bankach internetowych....? Ja nie.
Dlaczego to NIE zadziała (z dokładnością do tych sytuacji, kiedy zadziała)Nie zadziała to dlatego, że autor tego pomysłu nie zwrócił uwagi na taki jeden drobny mankament. Ten mankament nazywa się same origin policy. Po prostu w normalnej sytuacji przeglądarka nie pozwoli obiektowi XMLHTTPRequest z jednej strony odwołać się do innej strony. Tak więc umieszczając tak spreparowaną stronę na jakimś serwerze, atakujący nie osiągnie swojego celu, ponieważ wbudowane w przeglądarki mechanizmy zabezpieczeń spowodują, że skrypt nie dostanie się do atakowanego serwisu, ponieważ zablokuje to wspomniana zasada.
Dlaczego to może zadziałać...bo poza same origin policy jest jeszcze pomysł stref zabezpieczeń stosowany w Internet Explorer. W zależności od tego, w jakiej strefie znajduje się dana strona, może istnieć możliwość odwołania się do innych stron. Więcej informacji można znaleźć w artykule About Native XMLHTTP, szczególnie w sekcji Security: Cross-Domain and Zone Policy. Czego się tam dowiadujemy? Że strefa bardziej zaufana, może odwołać się do strefy mniej zaufanej. Teoria jest dobra, te strony, którym ufamy, nie powinny nam robić "złych rzeczy", ale jak normalny użytkownik ma określić jakiej stronie ma ufać na tyle, by ją dodać do zaufanych stron? Nie wspomnę już o tym, że strony lokalne (ze strefy Local Machine) są najbardziej zaufane. I właśnie dlatego pomysłodawca całego tematu testujący całą rzecz na swoim lokalnym komputerze mógł osiągnąć tak przerażające wyniki.
Warto zwrócić uwagę jeszcze na jedną rzecz - w przypadku gdy obiekt XMLHTTPRequest jest otrzymywany za pomocą MSXML 3.0, istnieje możliwość wysyłania żądań pomiędzy innymi protokołami, co prawda z ograniczeniem do HTTP i HTTPS, ale stwarza to pewne ryzyko. Na czym ono polega? Ważne aplikacje zwykle udostępniane są po protokole HTTPS. Aplikacje te są testowane, prawdopodobieństwo wystąpienia luk w nich jest stosunkowo niskie (bo jakieś zawsze się znajdą, ale najbardziej oczywiste zostały wychwycone w trakcie testów). Mniej istotne części serwisu dostępne są często po HTTP, a do ich bezpieczeństwa przywiązuje się mniejszą wagę. Może okazać się, że gdy w części "niebezpiecznej" serwisu wystąpi błąd, może on pozwolić na atak według powyższego scenariusza na jego bezpieczną część. Ale to już jest cross-site scripting, a o tym miałem nie pisać :)