Co to jest XSS?

Autor: Opublikowano

W skrócie: XSS (Cross-Site Scripting) to podatność, przez którą przeglądarka uruchamia niezaufany kod w kontekście odwiedzanej strony. Powstaje najczęściej wtedy, gdy aplikacja traktuje dane użytkownika jak fragment strony lub kodu zamiast jak zwykły tekst. Ochrona polega przede wszystkim na bezpiecznym wyświetlaniu danych, a nie tylko na blokowaniu podejrzanych wpisów.

Jak działa XSS i co może zrobić atakujący

Przeglądarka interpretuje HTML jako strukturę strony, a JavaScript jako instrukcje do wykonania. Jeśli aplikacja wstawi niezweryfikowaną treść w miejsce interpretowane jako kod, atakujący może wpłynąć na działanie strony u innego użytkownika. Źródłem takiej treści bywa komentarz, parametr adresu, nazwa profilu albo odpowiedź z zewnętrznej usługi.

Kod wykonany przez XSS działa w kontekście zaatakowanej witryny. Może odczytywać dostępne dane ze strony, zmieniać jej zawartość, wyświetlać fałszywy formularz logowania lub wykonywać operacje z uprawnieniami zalogowanego użytkownika. Rzeczywiste skutki zależą od funkcji aplikacji i zastosowanych zabezpieczeń.

Nie oznacza to automatycznie przejęcia serwera ani całego komputera. Problem dotyczy przede wszystkim zaufania przeglądarki do kodu uruchamianego przez daną witrynę. Użytkownik może otworzyć prawidłowy adres i mimo to trafić na stronę zawierającą złośliwą treść.

Trzy najczęściej opisywane postacie XSS

Podział pomaga ustalić, skąd pochodzi niebezpieczna treść i w którym miejscu aplikacja ją przetwarza:

Te określenia nie zawsze są rozłączne. „Zapisany” i „odbity” opisują głównie drogę dostarczenia danych, a „DOM-based” wskazuje miejsce niebezpiecznego przetwarzania. Treść przechowywana w bazie również może doprowadzić do DOM-based XSS.

Prosty przykład: tekst potraktowany jak HTML

Załóżmy, że aplikacja wyświetla nazwę użytkownika. Poniższy przykład uruchamiaj wyłącznie we własnym środowisku testowym lub tam, gdzie masz wyraźną zgodę:

const nazwa = '<img src="x" onerror="alert(\'Test XSS\')">';
const element = document.querySelector('#powitanie');
element.innerHTML = nazwa;

Właściwość innerHTML zleca przeglądarce zinterpretowanie wartości jako HTML. Jeśli obraz nie zostanie załadowany, obsługa błędu może uruchomić alert, czyli wyświetlenie okna z komunikatem. To demonstracja wykonania kodu, nie przykład kradzieży danych; dodatkowe zabezpieczenia przeglądarki lub strony mogą ją zablokować.

Jeśli nazwa ma być zwykłym tekstem, właściwym rozwiązaniem jest:

const nazwa = '<img src="x" onerror="alert(\'Test XSS\')">';
const element = document.querySelector('#powitanie');
element.textContent = nazwa;

Właściwość textContent wyświetli podany ciąg znaków bez tworzenia obrazu i bez wykonywania zawartej w nim instrukcji. Różnica jest zasadnicza: dane pozostają danymi. Nie trzeba zgadywać, które słowa lub znaczniki mogą być niebezpieczne.

Jak chronić aplikację przed XSS

Dobieraj ochronę do miejsca użycia danych. Kodowanie wyjścia polega na przedstawianiu znaków specjalnych tak, aby nie były interpretowane jako składnia. Innych zasad wymaga tekst w HTML, innych wartość atrybutu, adres URL czy fragment JavaScript. Zamiana samych nawiasów < i > nie zabezpiecza wszystkich tych sytuacji.

Gdy wyświetlasz zwykły tekst, korzystaj z bezpiecznych mechanizmów szablonów oraz interfejsów takich jak textContent. Automatyczne kodowanie w frameworku pomaga, ale można je ominąć funkcją wstawiającą surowy HTML. Takie wyjątki wymagają osobnej kontroli.

Jeżeli użytkownicy rzeczywiście potrzebują formatowania HTML, zastosuj utrzymywaną bibliotekę do sanityzacji, np. DOMPurify. Sanityzacja usuwa niedozwolone elementy i atrybuty według określonych reguł. Własny filtr oparty na kilku wyrażeniach regularnych nie jest równoważną ochroną.

Walidacja, czyli sprawdzanie dopuszczalnego formatu danych, pozostaje przydatna: pole wieku powinno przyjmować liczbę, a adres odnośnika dozwolony schemat. Nie zastępuje jednak bezpiecznego wyświetlania. Zabezpieczenie tylko formularza też nie wystarcza, bo dane mogą trafić do aplikacji inną drogą.

Dodatkowe warstwy ograniczają skutki błędów. CSP (Content Security Policy) pozwala określić zasady wykonywania skryptów, ale jej skuteczność zależy od konfiguracji. Atrybut HttpOnly blokuje odczyt ciasteczka przez JavaScript, lecz nie uniemożliwia złośliwemu kodowi wykonywania wszystkich działań w aktywnej sesji.

Od czego zacząć sprawdzanie własnej strony

Prześledź jedno pole od przyjęcia danych do każdego miejsca ich wyświetlania. Komentarz może być bezpieczny pod artykułem, a niebezpieczny w panelu moderacji lub podglądzie powiadomienia. Sprawdź też użycia innerHTML i funkcji pozwalających omijać automatyczne kodowanie.

Następny krok to test w odizolowanym środowisku: ustal, czy wpisana treść pojawia się jako tekst, czy zmienia strukturę strony. Po poprawce dodaj test regresyjny, który wykryje ponowne potraktowanie tych danych jak HTML.

Zobacz też: Co to jest 2FA?

Przeczytaj także

Dowiedz się, jak PHP-FPM obsługuje żądania PHP, czym różni się od serwera WWW i jak dobrać ustawienia procesów do ruchu oraz zasobów hostingu.
Poznaj BIND, otwarte oprogramowanie serwera DNS: sprawdź, jak obsługuje domeny, czym różnią się jego role i kiedy warto samodzielnie go wdrożyć.
Poznaj najważniejsze Security Headers, ich rolę w ochronie strony oraz sposób sprawdzania i wdrażania nagłówków bez blokowania potrzebnych funkcji.