
💡 Cross-site scripting (XSS): czym jest i jak chronić witrynę w 2026 roku
У 2019 roku prawie 75% dużych firm zetknęło się z cross-site scriptingiem. Siedem lat później XSS nigdzie nie zniknął. Microsoft zaraportował 970 przypadków XSS załatanych tylko od stycznia 2024, a jedna podatność z 2025 roku we wtyczce LiteSpeed Cache zagroziła 7 milionom stron na WordPressie.
Problem nie leży w technologii. JavaScript to język interaktywnego webu, bez niego nie działa żaden motyw, żaden formularz komentarzy, żaden koszyk sklepu internetowego. Problem polega na tym, że atakujący może zmusić Pana/Pani stronę do wykonania swojego kodu, a przeglądarka nie odróżni szkodliwego skryptu od legalnego.
Rozłożymy na czynniki pierwsze mechanikę XSS, trzy typy ataków i konkretne warstwy ochrony, które zamykają stronę przed cross-site scriptingiem. Z narzędziami, przykładami kodu i rzeczywistymi przypadkami z WordPressa.
💡 Szybki przegląd:
- Czym jest XSS i jak atakujący wstrzykuje szkodliwy kod na zaufaną stronę
- Trzy typy cross-site scriptingu: stored, reflected i DOM-based, i czym się różnią
- Konfiguracja krok po kroku trzech warstw ochrony: WAF, eskejpowanie danych wyjściowych i Content Security Policy
- Gdzie szukać podatności XSS na swojej stronie i co robić, gdy atak już nastąpił
Czym jest cross-site scripting

Cross-Site Scripting to atak iniekcyjny, w którym atakujący wstrzykuje szkodliwy skrypt na stronę zaufanego serwisu. Przeglądarka ofiary wykonuje ten kod, ponieważ postrzega go jako część legalnej strony. Stąd nazwa: skrypt przychodzi „z przekroczeniem granicy witryny" (crossing site boundary).
Technicznie wektor ataku nie ogranicza się do JavaScriptu. Podatności są możliwe w HTML, Flashu, ActiveX i CSS. Jednak w praktyce zdecydowana większość exploitów celuje właśnie w JS. Powód: dostęp do drzewa DOM, ciasteczek, localStorage i możliwość wykonywania żądań w imieniu użytkownika.
W WordPressie podatność prawie zawsze powstaje przez wtyczki i motywy, które nieprawidłowo obsługują dane wprowadzane przez użytkownika. Formularze komentarzy, paski wyszukiwania, formularze kontaktowe, strony logowania, każde pole, które przyjmuje dane i wyświetla je z powrotem bez filtrowania, staje się punktem wejścia. Według danych firmy Claranet, w 2024 roku znaleziono 2570 przypadków reflected i stored XSS w sprawdzonych aplikacjach webowych.
Jak działa XSS
Atakujący potrzebuje dwóch warunków: punktu wejścia dla szkodliwego kodu i braku filtrowania na wyjściu. W praktyce realizuje się to dwiema drogami: poprzez manipulację danymi wprowadzanymi przez użytkownika i poprzez obejście same-origin policy.
Wstrzykiwanie przez dane wprowadzane przez użytkownika
Najczęstszy scenariusz. Pole użytkownika, pasek wyszukiwania, formularz komentarza, pole przesyłania pliku przyjmuje nie tylko tekst, ale i kod wykonywalny. Jeśli wtyczka lub motyw nie eskepują danych wyjściowych, wprowadzony <script>alert('XSS')</script> wykona się w przeglądarce każdego, kto otworzy stronę.
Problem jest głębszy, niż się wydaje. Nawet doświadczeni programiści przeoczają wektory XSS przez pozornie niewinne pola: przesłanie pliku SVG z osadzonym skryptem, wpis w polu „nazwa użytkownika" podczas rejestracji, parametry URL w przekierowaniach. Jedno pole bez esc_url() lub esc_attr() i strona jest otwarta.
W idealnym świecie pole wyszukiwania przyjmuje zwykły tekst i nic więcej. W rzeczywistym WordPressie ekosystem 60 000+ wtyczek czyni tę gwarancję nieosiągalną, wystarczy jedna wtyczka z echo $_GET['q'] bez esc_html().
Obejście same-origin policy

Same-origin policy to fundamentalna zasada bezpieczeństwa przeglądarek: skrypty z jednego źródła nie mogą odczytywać danych z innego. Strona Facebooka i strona banku, otwarte w tej samej przeglądarce, nie wymieniają się informacjami. Ale ta zasada ma piętę achillesową: ciasteczka sesyjne.
Kiedy loguje się Pan/Pani na stronę, przeglądarka tworzy ciasteczko sesyjne, które potwierdza Pana/Pani tożsamość przy każdym żądaniu. Bez niego musiałby Pan/musiałaby Pani wpisywać hasło przy przejściu na każdą nową podstronę. Problem w tym, że przeglądarka dołącza to ciasteczko do każdego żądania do domeny, w tym do żądań zainicjowanych przez szkodliwy skrypt.
Schemat ataku: atakujący znajduje podatność XSS na stronie example.com → wstrzykuje skrypt, który odczytuje document.cookie → wysyła ciasteczko sesyjne na swój serwer. Rezultat: pełny dostęp do konta ofiary bez znajomości hasła. Ciasteczka sesji przechowują dane logowania, zawartość koszyka, informacje o dostawie, cały kontekst użytkownika.
Trzy typy ataków XSS

Klasyfikacja XSS opiera się na tym, gdzie i jak szkodliwy kod trafia do ofiary. Wyróżnia się trzy typy i aby chronić witrynę, należy rozumieć mechanikę każdego z nich.
Przechowywany XSS (Stored, typ I)
Najniebezpieczniejszy typ. Szkodliwy skrypt jest przechowywany na serwerze: w bazie danych, logach, polu komentarza i wykonuje się za każdym razem, gdy otwierana jest zainfekowana strona. W WordPressie to klasyczny scenariusz: atakujący zostawia komentarz ze znacznikiem <script>, wtyczka komentarzy nie filtruje HTML-a i skrypt uruchamia się u każdego odwiedzającego wpis.
Cechą przechowywanego XSS jest to, że ataku nie trzeba aktywować za pomocą linku phishingowego. Ofiara po prostu wchodzi na stronę. W 2025 roku podatność CVE-2025-12709 we wtyczce Interactions dla WordPressa, klasyczny stored XSS przez niedostateczną sanityzację danych wejściowych w selektorach zdarzeń.
Odbity XSS (Reflected, typ II)
Atakujący wysyła ofierze link zawierający szkodliwy kod w parametrach URL. Serwer „odbija" ten kod z powrotem w odpowiedzi, na przykład w komunikacie błędu wyszukiwania lub w wierszu „Szukałeś: X". Przeglądarka wykonuje skrypt, ponieważ pochodzi on z treści odpowiedzi z zaufanego serwera.
Odbity XSS wymaga aktywnego działania ofiary, kliknięcia linku. Dlatego atak często maskuje się jako legalny URL w wiadomości phishingowej. W WordPressie typowym wektorem są wtyczki wyszukiwania, które wyświetlają zapytanie bez esc_html().
DOM-based XSS (typ 0)
W przeciwieństwie do dwóch pierwszych, tutaj podatność znajduje się nie w kodzie serwerowym, a w klienckim JavaScripcie. Szkodliwe dane nigdy nie trafiają na serwer, są przetwarzane bezpośrednio w przeglądarce za pomocą niebezpiecznych metod DOM-API, takich jak innerHTML, document.write() czy eval().
Źródłem danych jest URL (przez window.location), document.referrer lub dowolne inne kontrolowane źródło po stronie klienta. Logi serwerowe są czyste, atak widać tylko w przeglądarce. Wykrycie takiego XSS jest najtrudniejsze, ponieważ WAF i skanery serwerowe go nie widzą.
Dlaczego XSS jest szczególnie niebezpieczny dla WordPressa
WordPress to cel numer jeden dla XSS z jednego powodu: ekosystem. Przy ponad 60 000 wtyczek w repozytorium nie wszystkie przechodzą ścisłą weryfikację pod kątem escapowania danych wyjściowych. Jedna podatna wtyczka kompromituje całą witrynę.
We wrześniu 2025 roku Microsoft opublikował analizę tego, dlaczego XSS pozostaje zagrożeniem 25 lat po swoim pojawieniu się. Kluczowy wniosek: złożoność współczesnego webstacku sprawia, że całkowite wyeliminowanie XSS jest prawie niemożliwe, zbyt wiele warstw, w których escapowanie może zostać pominięte.
Co atakujący uzyskuje przez XSS na WordPressie:
- Dostęp do panelu administracyjnego przez kradzież sesyjnych cookies administratora
- Wstawianie ukrytych linków (SEO-spam)
- Pobieranie szkodliwego oprogramowania na komputer odwiedzającego
- Podmianę danych płatniczych w WooCommerce
- Masowy deface stron witryny
W połączeniu z socjotechniką XSS staje się wektorem dla złożonych ataków: od instalacji keyloggerów po fałszowanie żądań międzywitrynowych.
Jak chronić witrynę przed XSS: trzy warstwy

Ochrona przed XSS nie sprowadza się do jednego ustawienia. Działa tylko obrona warstwowa: wtyczki bezpieczeństwa blokują zgrubne ataki, eskejpowanie wyjścia zamyka techniczne wektory, a Content Security Policy blokuje wykonanie skryptów na poziomie przeglądarki.
Warstwa 1: wtyczki bezpieczeństwa i firewall
Pierwsza linia obrony, wtyczka WordPress z Web Application Firewall. WAF filtruje przychodzące żądania, zanim dotrą one do kodu wtyczek, i blokuje znane sygnatury ataków XSS.
Wybierając wtyczkę bezpieczeństwa, kieruj się poniższą listą kontrolną:
- Regularne skanowanie w poszukiwaniu złośliwego oprogramowania i znanych CVE w zainstalowanych wtyczkach
- Firewall z regułami blokowania wzorców XSS w żądaniach
- Hartowanie WordPressa: wyłączenie XML-RPC, zmiana prefiksu tabel, zablokowanie edycji plików z panelu administracyjnego
- Scentralizowane zarządzanie aktualizacjami wszystkich wtyczek i motywów
- Tworzenie kopii zapasowych, aby odtworzyć witrynę, jeśli atak jednak się powiedzie
Zestawienia wtyczek bezpieczeństwa WordPress ze szczegółowym omówieniem funkcji każdego narzędzia proszę szukać w branżowych przeglądach na naszej stronie.
Warstwa 2: walidacja i eskejpowanie wyjścia
To główna linia obrony technicznej. Zasada jest prosta i nie podlega dyskusji: żadne dane użytkownika nie trafiają do przeglądarki bez eskejpowania. WordPress udostępnia do tego wbudowane funkcje, a każda z nich jest przypisana do konkretnego kontekstu wyjścia.
Podstawowy arsenał programisty WordPress:
1 // Для вывода внутри HTML-тегов — между <p> и </p> 2 echo esc_html($user_input); 3 4 // Для атрибутов HTML — внутри value="..." 5 echo esc_attr($user_input); 6 7 // Для URL в href, src и других атрибутах 8 echo esc_url($user_url); 9 10 // Для вывода текста внутри <textarea> 11 echo esc_textarea($user_text); 12 13 // Для JavaScript-переменных 14 echo esc_js($user_data); 15 16 // Для разрешенных HTML-тегов с удалением опасных атрибутов 17 echo wp_kses_post($user_html);
Kluczowa kwestia: wybór funkcji zależy od kontekstu. esc_html() w atrybucie href nie pomoże, atakujący wstawi javascript:alert('XSS'). I odwrotnie, esc_url() wewnątrz akapitu przepuści znacznik <script>. Kontekst determinuje funkcję.
Osobno warto wspomnieć o wp_kses(), potężnym filtrze, który przepuszcza tylko dozwolone znaczniki HTML i atrybuty. Dla treści tworzonych przez użytkowników (komentarze, opisy profili, pola niestandardowe) jest to minimalny wymagany poziom filtracji.
Warstwa 3: Content Security Policy (CSP)
CSP, nagłówek HTTP, który mówi przeglądarce: „Wykonuj skrypty tylko z tych źródeł". To ostatnia linia obrony. Nawet jeśli atakujący wstrzyknął <script> na stronę, przeglądarka go nie wykona, ponieważ skrypty inline nie znajdują się na białej liście.
Podstawowa polityka CSP dla WordPressa:
1 // В functions.php или через плагин 2 function add_csp_header() { 3 header("Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:;"); 4 } 5 add_action('send_headers', 'add_csp_header');
Rygorystyczna polityka ('strict-dynamic' zamiast 'unsafe-inline') jest bezpieczniejsza, ale wymaga skonfigurowania nonce lub hashy dla każdego legalnego skryptu, a to duży nakład pracy na stronie z kilkunastoma aktywnymi wtyczkami. Proszę zacząć od trybu report-only, aby zebrać logi naruszeń i nie uszkodzić frontendu:
1 Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report-endpoint
CSP nie zastępuje eskejpowania. Łagodzi skutki błędu, gdy eskejpowanie zostało gdzieś pominięte.
Wideo: XSS od podstaw do eksploitacji
Aby zobaczyć XSS w działaniu i zrozumieć, jak szukać podatności na rzeczywistych stronach, proszę obejrzeć to 30-minutowe omówienie:
Po obejrzeniu proszę wrócić do warstw ochrony powyżej, teraz będą one zrozumiałe na poziomie mechaniki, a nie tylko na poziomie nazw funkcji.
⁉️🤔 Często zadawane pytania
Czy aktualizacja WordPressa i wtyczek pomoże chronić przed XSS?
Tak, i jest to najbardziej niedoceniany krok ochrony. Każda nowa wersja wtyczki często zamyka konkretne CVE, w tym podatności XSS. Podatność LiteSpeed Cache CVE-2025-12450 została załatana w ciągu tygodnia od wykrycia, ale 7 milionów witryn, które nie dokonały aktualizacji, pozostało otwartych na atak. Proszę włączyć automatyczne aktualizacje dla wszystkich wtyczek, utrata kompatybilności zdarza się rzadko, a pominięta łatka uderza z pewnością.
Czy jedna wtyczka bezpieczeństwa wystarczy do ochrony przed XSS?
Nie. Wtyczka bezpieczeństwa z WAF zamyka znane sygnatury ataków, ale nie widzi podatności zero-day ani niestandardowych wektorów. Powinna być pierwszą warstwą, za którą idą eskejpowanie wyjścia w kodzie motywu i nagłówki CSP. Trzy warstwy razem dają ochronę, której nie zapewni żadna z nich osobno.
Jak sprawdzić, czy na mojej stronie są podatności XSS?
Proszę zacząć od darmowego skanera, WPScan, Sucuri SiteCheck, Qualys SSL Labs. W celu głębszej weryfikacji proszę uruchomić OWASP ZAP (Zed Attack Proxy), narzędzie open-source, które automatycznie fuzzuje pola wejściowe i wyłapuje odbite XSS. Ważne: automatyczne skanery nie widzą DOM-based XSS, do tego potrzebny jest ręczny audyt kodu JavaScript witryny.
Czy można całkowicie wyeliminować XSS na dużej stronie?
Całkowite wyeliminowanie XSS na stronie z dziesiątkami wtyczek i niestandardowym motywem to zadanie bliskie ideałowi, ale trudne do pełnego osiągnięcia. Każda nowa wtyczka, każda aktualizacja motywu, każdy niestandardowy snippet w
functions.phpto potencjalny punkt wejścia. Realistyczny cel: trzy warstwy ochrony, automatyczne aktualizacje, kwartalny audyt i CSP w trybie report-only. W ten sposób wyłapią Państwo przeważającą większość ataków na wczesnym etapie.
Co robić, jeśli strona została już zaatakowana przez XSS?
Należy natychmiast zmienić wszystkie hasła i zresetować klucze sesyjne w
wp-config.phpza pomocą generatora WordPress. Następnie proszę odtworzyć witrynę z czystej kopii zapasowej. Po odtworzeniu proszę zainstalować wtyczkę bezpieczeństwa, zaktualizować wszystkie wtyczki i motywy do najnowszych wersji, dodać nagłówek CSP wfunctions.php. Zmiana haseł jest konieczna, ponieważ XSS często kradnie sesyjne cookies administratora.
XSS i SQL injection, czy to to samo?
Nie, choć oba należą do ataków typu injection. SQL injection uderza w bazę danych poprzez zapytanie SQL, atakujący może odczytać, zmienić lub usunąć tabele. XSS uderza w przeglądarkę użytkownika poprzez JavaScript, celem jest kradzież sesji, wyświetlenie formularza phishingowego, podmiana treści strony. Mają one różne wektory, różne funkcje ochrony (
$wpdb->prepare()dla SQL,esc_html()dla XSS) i różne konsekwencje. Ale w praktyce często idą w parze: XSS wykorzystuje się do dostarczenia SQL injection przez panel administracyjny.
Czy należy bać się XSS w 2026
XSS nie zniknął, ale ochrona przed nim stała się rutyną inżynieryjną, a nie magią. Trzy warstwy, wtyczka z WAF, eskejpowanie wyjścia we wszystkich punktach kontaktu z użytkownikiem i nagłówek CSP, zamykają przeważającą większość wektorów. Do tego automatyczne aktualizacje wtyczek i motywów, aby łatki docierały szybciej niż exploity.
Jeśli w tej chwili nie korzystają Państwo z żadnej z tych warstw, proszę zacząć od zainstalowania wtyczki bezpieczeństwa i włączenia automatycznych aktualizacji w panelu administracyjnym WordPressa. Zajmie to 10 minut i zamknie najbardziej prymitywne wejścia. A potem proszę wrócić do tego artykułu, gdy będą Państwo gotowi wdrożyć eskejpowanie i CSP.



