Reflected XSS
| Po angielsku | reflected XSS |
|---|---|
| Którą formą pisać | po angielsku Polski odpowiednik istnieje, ale w praktyce nikt tak nie pisze. Zostaw angielski, polski trzymaj jako synonim. |
| Inne formy | odbity XSS |
| Kategoria | Podatności i klasy błędów |
Reflected XSS to odmiana XSS (Cross-Site Scripting), w której skrypt przekazany w żądaniu HTTP, najczęściej w adresie URL, zostaje od razu odesłany w odpowiedzi strony i wykonuje się w przeglądarce osoby, która otworzyła spreparowany link. MITRE nazywa ją typem 1 lub XSS nietrwałym i opisuje jako sytuację, w której aplikacja serwerowa czyta dane wprost z żądania HTTP i odbija je w odpowiedzi [1]. PortSwigger definiuje ją podobnie: aplikacja otrzymuje dane w żądaniu i w niebezpieczny sposób umieszcza je w natychmiastowej odpowiedzi [2].
Jak działa
Ładunek nie jest nigdzie zapisywany. Istnieje tylko w żądaniu, dlatego atakujący musi skłonić ofiarę, by to żądanie sama wysłała. MITRE wskazuje, że najczęstszym sposobem jest umieszczenie złośliwej treści w parametrze adresu URL, który zostaje opublikowany albo wysłany ofierze pocztą [1]. Tak zbudowane adresy stanowią według MITRE rdzeń wielu schematów phishingu [1].
Przebieg ataku pokazuje schemat poniżej.
Odbicie może nastąpić w treści strony, w atrybucie znacznika albo wewnątrz skryptu. PortSwigger podkreśla, że miejsce, w którym dane trafiają do odpowiedzi, decyduje o tym, jaki ładunek jest potrzebny, i może wpływać na skutki podatności [2].
Odmiany i porównanie
MITRE wyróżnia trzy główne typy XSS [1]. Różnica między wariantem odbitym a zapisanym dotyczy tego, kiedy dane trafiają na stronę: przy reflected XSS w odpowiedzi na to samo żądanie, przy Stored XSS w późniejszej odpowiedzi, po zapisaniu na serwerze [2].
| Cecha | Reflected XSS | Stored XSS | DOM-based XSS |
|---|---|---|---|
| Gdzie jest ładunek | w żądaniu HTTP [1] | w bazie lub pliku [1] | w kodzie strony po stronie klienta [1] |
| Kiedy trafia na stronę | w natychmiastowej odpowiedzi [2] | w późniejszej odpowiedzi [2] | po przetworzeniu przez skrypt [1] |
| Potrzebny link do ofiary | tak [1] | nie, wystarczy wyświetlenie [1] | zależy od źródła danych |
Zdaniem PortSwigger reflected XSS ma zwykle mniejsze skutki niż stored XSS, bo wymaga zewnętrznego mechanizmu dostarczenia ładunku [2]. Trzeci wariant, DOM-based XSS, powstaje w całości w przeglądarce.
W WordPressie
W WordPressie odbity XSS pojawia się tam, gdzie wtyczka albo motyw wypisuje wartość z $_GET lub $_REQUEST bez kodowania; zob. podatność we wtyczce. Szczególnie groźne są strony panelu administracyjnego, bo skrypt działa wtedy z uprawnieniami zalogowanego administratora.
Dokumentacja WordPressa definiuje escapowanie jako zabezpieczanie danych wyjściowych i zaleca kodowanie jak najbliżej miejsca wypisania [4]. Funkcję dobiera się do kontekstu, w którym trafia wartość [4]. To samo mówi OWASP: kodowanie wyjścia sprawia, że dane wyświetlają się jako tekst, a nie wykonują jako kod, a każdy kontekst wymaga innego kodowania [3].
| Kontekst odbicia | Kodowanie według OWASP | Funkcja WordPressa |
|---|---|---|
| treść elementu HTML | encje HTML [3] | esc_html() [4] |
| wartość atrybutu | encje HTML, wartość w cudzysłowie [3] | esc_attr() [4] |
| adres URL | kodowanie procentowe [3] | esc_url() [4] |
| JavaScript w linii | sekwencje Unicode [3] | esc_js() [4] |
Częstą pułapką jest funkcja add_query_arg(). Jej dokumentacja ostrzega, że zwracana wartość nie jest domyślnie kodowana i przed wypisaniem trzeba ją przepuścić przez esc_url() lub podobną funkcję, aby uniknąć XSS [5]. Pominięcie adresu w wywołaniu oznacza użycie bieżącego adresu z $_SERVER['REQUEST_URI'] [5], więc parametry podane przez użytkownika trafiają do budowanego linku.
// podatne: adres zbudowany z bieżącego żądania wypisany bez kodowania
echo '<a href="' . add_query_arg( 'strona', 2 ) . '">Dalej</a>';
// poprawne: kodowanie tuż przed wypisaniem
echo '<a href="' . esc_url( add_query_arg( 'strona', 2 ) ) . '">Dalej</a>';
Zagrożenia i skutki
Skrypt uruchomiony w przeglądarce ofiary działa w kontekście witryny. PortSwigger wylicza, że atakujący może wtedy wykonać każdą czynność, którą może wykonać użytkownik, zobaczyć i zmienić dane dostępne dla użytkownika oraz inicjować interakcje z innymi użytkownikami aplikacji [2]. MITRE wymienia ujawnienie informacji z ciasteczek i danych sesji oraz kradzież lub manipulację ciasteczkami [1].
- Przejęcie sesji przez odczyt tokenu sesyjnego, jeśli ciasteczko nie ma odpowiednich flag.
- Działania w panelu w imieniu administratora, w tym zmiany ustawień i kont; zob. role i uprawnienia użytkowników.
Jak się bronić
Podstawą jest kodowanie wyjścia dopasowane do kontekstu i walidacja wejścia [2]. W WordPressie oznacza to funkcje esc_* użyte przy każdym wypisaniu wartości z żądania oraz sanityzacja danych wejściowych przy odczycie [4]. OWASP zaleca też unikanie wstawiania danych w niebezpieczne miejsca, takie jak znaczniki skryptu czy atrybuty obsługi zdarzeń [3].
Drugą warstwą jest CSP (Content Security Policy). MDN opisuje Content Security Policy jako zestaw instrukcji od witryny do przeglądarki, który ogranicza to, co kod strony może robić, i służy głównie ochronie przed XSS [6]. MDN zaznacza, że CSP nie zastępuje czyszczenia danych wejściowych [6], a OWASP traktuje ją jako warstwę obrony, nie jako obronę główną [3]. Filtry typu WAF mogą zatrzymać znane ładunki w parametrach, ale nie naprawiają kodu.
Historia i przykłady
CERT Polska 2 czerwca 2026 roku opisał podatność CVE-2026-34907 w systemie Wirtualna Uczelnia firmy Simple SA: parametr locale w wielu punktach końcowych pozwalał osadzić JavaScript, który wykonywał się, gdy ofiara otworzyła link [7]. Ta sama publikacja opisuje wstrzyknięcie szablonu po stronie serwera, CVE-2026-34906 [7].
Wcześniej, 10 lipca 2024 roku, CERT Polska opublikował informację o podatnościach w projekcie Phoniebox w wersjach do 2.7 włącznie [8]. Luka CVE-2024-3798 pozwalała na wstrzyknięcie poleceń przez parametr file, a przy okazji umożliwiała ataki typu Reflected XSS i CSRF (Cross-Site Request Forgery) [8].
Przypisy
8- [1] CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') · MITRE
- [2] Reflected XSS — Web Security Academy · PortSwigger
- [3] Cross Site Scripting Prevention Cheat Sheet · OWASP
- [4] Escaping Data — Common APIs Handbook · WordPress.org
- [5] add_query_arg() — Function · WordPress.org
- [6] Content Security Policy (CSP) · MDN Web Docs
- [7] Podatności w oprogramowaniu Wirtualna Uczelnia (CVE-2026-34906, CVE-2026-34907) · CERT Polska
- [8] Podatności w oprogramowaniu Phoniebox (CVE-2024-3798, CVE-2024-3799) · CERT Polska