Atak hakerski na stronę WordPress: czego nie da się cofnąć po incydencie

Atak hakerski na stronę WordPress: czego nie da się cofnąć po incydencie

Zawirusowanie strony internetowej rzadko kończy się na komunikacie od hostingu albo spadku wydajności.

Prawdziwe konsekwencje pojawiają się później – wtedy, gdy strona ma realizować swoje realne cele: generować leady, wspierać sprzedaż albo budować wiarygodność firmy. Czyli dokładnie to, do czego w ogóle została stworzona.

W ostatnim czasie zajmowałem się odzyskiwaniem strony, która padła ofiarą kombinacji kilku „niewinnych” decyzji:

  • braku aktualizacji,
  • chaotycznego kodu,
  • nieprzetestowanych formularzy,
  • oraz fragmentów kodu wygenerowanych i wdrożonych bez pełnego zrozumienia ich działania.

Typowy vibe coding - działało, więc zostało. Do czasu, kiedy przestała działać cała strona, bo dostawca hostingu ją zablokował.

Problem w takich przypadkach nie kończy się na samym usunięciu zagrożenia i przez nadpisanie i usunięcie zawirusowanych plików.

Im większa strona i im mniej uporządkowana jej struktura, tym trudniej znaleźć faktyczne źródło ataku. A strona, która raz została przejęta, bardzo często trafia na listę celów do ponownych prób włamań - automatycznych i regularnych.

Ten artykuł nie jest straszakiem ani manifestem przeciwko AI.
To techniczny zapis realnego przypadku, który pokazuje:

  • dlaczego „odzyskanie strony” to proces, a nie jednorazowa akcja,
  • jak brak standardów programistycznych utrudnia (i zwiększa koszty) ratowania serwisu,
  • oraz dlaczego nawet przy użyciu narzędzi AI ktoś musi rozumieć, co faktycznie ląduje na produkcji.
Ilustracja trzech dokumentów obok siebie; pierwszy ma ikonę szkła powiększającego, drugi jest pusty z zagiętym rogiem, a trzeci pokazuje kropkowany kontur z X, wszystkie na żółtym i białym tle.

Jak wyglądał proces odzyskania strony

Proces odzyskiwania strony został podzielony na etapy, zgodnie z ustaleniami z klientem – od działań minimalnych inwestycyjnie, których celem było szybkie przywrócenie działania serwisu, do dalszej, pogłębionej analizy w przypadku ponownego wystąpienia problemu.

Na pierwszym etapie kluczowe było ograniczenie skutków ubocznych dla elementów działających poza samą stroną internetową, takich jak kampanie reklamowe czy powiązania z narzędziami analityczno-marketingowymi (m.in. Google Site Kit, Microsoft Clarity). W takich przypadkach liczy się czas i stabilność – nie eksperymenty.

Zakres standardowego odzyskania obejmował:

  • aktualizację plików systemowych,
  • usunięcie wykrytych zagrożeń przy użyciu narzędzi antywirusowych,
  • weryfikację, czy na serwerze nie pojawiły się nadmiarowe pliki lub modyfikacje w pliku .htaccess,
  • przegląd elementów zainstalowanych w zapleczu strony.

Na tym etapie wspólnie z klientem została też przeanalizowana faktyczna użyteczność zainstalowanych komponentów. W praktyce okazało się, że na serwerze znajdowało się:

  • 7 szablonów,
  • około 15 wtyczek,

z czego realnie wykorzystywane były:

  • 1 szablon,
  • 7 wtyczek.

Pozostałe elementy zostały dodane wcześniej „przy okazji” – np. jako rekomendacje innych szablonów lub domyślne dodatki instalowane bez konkretnego zastosowania.

Po oczyszczeniu i uporządkowaniu środowiska strona wróciła do poprawnego działania. To potwierdziło, że pierwszy etap spełnił swój cel.
Jednocześnie ponowne pojawienie się problemu po pewnym czasie jasno wskazało, że źródło infekcji znajduje się poza standardowym zakresem typowych działań naprawczych i wymaga szerszego spojrzenia.

W takich sytuacjach potencjalnym źródłem problemu mogą być:

  • aktualnie używane wtyczki,
  • aktywny szablon,
  • elementy znajdujące się na serwerze, ale działające poza główną strukturą strony (do czego wrócimy za chwilę).
Kreskówkowy detektyw trzymający szkło powiększające stoi obok ekranu z kodem binarnym. Szkło powiększające podświetla słowo ERROR na czerwono wśród zer i jedynek.

Przyczyna i dlaczego nie była widoczna od razu.

Po wykluczeniu wpływu aktywnych wtyczek oraz szablonu – zgodnie z przyjętą kolejnością diagnostyczną – analiza została rozszerzona o elementy znajdujące się poza standardowym ekosystemem WordPressa.

Uwagę zwrócił formularz umieszczony na jednej z podstron, niebędącej stroną kontaktową. Sam formularz nie wyglądał podejrzanie i na pierwszy rzut oka nie odbiega od typowych rozwiązań stosowanych w działaniach marketingowych.

Kluczowy szczegół pojawiał się dopiero „pod maską”.
Dane z formularza były wysyłane do pliku send.php, znajdującego się w osobnym katalogu na serwerze, poza strukturą WordPressa.

Z punktu widzenia bezpieczeństwa był to moment graniczny:

  • formularz osadzony w WordPressie,
  • logika przetwarzania danych przeniesiona do własnego skryptu,
  • dodatkowy landing page działający niezależnie od CMS-a.

Sam formularz nie posiadał dodatkowych zabezpieczeń przed botami (captcha, honeypot, ograniczenia zapytań - temat szerzej opisany w osobnym artykule), co samo w sobie jest ryzykiem, ale niekoniecznie przyczyną infekcji. Nietypowe było opuszczenie spójnego środowiska WordPressa na rzecz autonomicznego skryptu, działającego bez jego mechanizmów ochronnych.

W trakcie dalszej analizy okazało się, że landing page, a konkretnie skrypt obsługujący wysyłkę danych został wygenerowany przy użyciu narzędzia AI. Jego celem było mierzenie zaangażowania użytkowników, czyli typowe działanie marketingowe. Problem polegał na tym, że kod został wdrożony bez dodatkowej walidacji, testów bezpieczeństwa i kontroli dostępu.

Po konsultacji z klientem, zgodnie z przyjętym podejściem minimalizacji ryzyka, zapadła decyzja o tymczasowym usunięciu tego elementu. Efekt był jednoznaczny - ataki ustały.

Warto tu podkreślić jedną rzecz: odzyskiwanie strony rzadko polega na jednym szybkim wskazaniu palcem źródła problemu. To proces eliminacji, który musi być prowadzony w określonej kolejności, tak aby nie powodować dodatkowych szkód.

W tym przypadku „szkodą” mogłyby być np.:

  • zerwane autoryzacje wtyczek,
  • utrata połączeń z narzędziami analitycznymi,
  • konieczność ponownej konfiguracji integracji marketingowych.

Własny skrypt vs ekosystem WordPress.

Czy korzystanie z własnego skryptu jest złe?
Klasyczna odpowiedź z branży IT brzmi: to zależy. Nie od technologii, tylko od świadomości tego, co robimy i jakie będą konsekwencje wdrożenia.

W opisywanym przypadku zastosowanie osobnego folderu z dedykowanym landing page’em nie było błędem koncepcyjnym. Taka separacja często bywa wręcz zaletą – ułatwia zmianę kodów marketingowych, testowanie wariantów czy szybkie wyłączanie elementu bez ingerencji w główną stronę.

Problem pojawił się w momencie, gdy własny skrypt znalazł się w bezpośrednim sąsiedztwie głównej instalacji WordPressa. W praktyce oznaczało to, że w przypadku przejęcia jednego elementu, zagrożenie mogło swobodnie „rozlać się” po całej strukturze serwera.

Tu właśnie widać przewagę dojrzałych rozwiązań opartych o wtyczki i sprawdzone mechanizmy CMS-a. Popularne narzędzia:

  • przechodzą testy na setkach lub tysiącach konfiguracji,
  • są aktualizowane pod kątem nowych podatności,
  • działają w ramach jasno określonego ekosystemu bezpieczeństwa.

Nie oznacza to, że landing page czy przekierowanie muszą być wykonane w WordPressie. Mogą działać poza nim - pod warunkiem, że są odizolowane, przetestowane i utrzymywane jak pełnoprawna aplikacja. W przeciwnym razie pojawia się klasyczny problem vibe codingu: kod „działa”, ale nikt nie kontroluje, co dokładnie robi i jakie ryzyko generuje dla całej strony oraz wizerunku firmy.

Z doświadczenia wynika, że w wielu przypadkach atak nie dotyka najbardziej oczywistych elementów strony. Baza danych bardzo rzadko ulega uszkodzeniu, co oznacza, że treści, ustawienia czy struktura serwisu zwykle pozostają nienaruszone. Podobnie wygląda to w przypadku grafik, zdjęć oraz plików dodanych do wpisów i podstron.

To właśnie dlatego po „technicznym” oczyszczeniu strony łatwo odnieść wrażenie, że tak naprawdę nic poważnego się nie stało.

Problem polega na tym, że najbardziej dotkliwe konsekwencje ataku nie znajdują się w plikach ani w bazie danych. Są nimi rzeczy, których nie da się w prosty sposób odzyskać ani odtworzyć:

  • utracone dane analityczne,
  • przerwane ścieżki konwersji,
  • niewysłane formularze i utracone zapytania,
  • spadek zaufania użytkowników oraz algorytmów.

To straty, które trudno zmierzyć i jeszcze trudniej jednoznacznie przypisać do konkretnego momentu. A to sprawia, że często są bagatelizowane. W praktyce jednak brak tych danych i kontaktów boli bardziej niż utrata samej strony, bo nie da się ich „przywrócić z kopii zapasowej”.

W opisywanym przypadku doszedł jeszcze jeden element: zerwanie powiązania z narzędziami marketingowymi, działającymi w oparciu o autoryzację OAuth. Integracje formalnie istniały, ale przestały działać poprawnie, co oznaczało brak ciągłości pomiarów i niepełny obraz zachowania użytkowników.

Z pozoru drobiazg. W praktyce – luka w danych, której nie da się już uzupełnić.

W żółtym folderze oznaczonym WP Content znajduje się smutna twarz dokumentu z brakującymi pikselami u góry, z lupą na folderze, a wszystko to na żółtym tle z delikatną ikoną błędu.

Jak dziś rekomenduję zabezpieczać formularze i stronę.

Zabezpieczenia nie działają zero-jedynkowo. Nie ma jednego „magicznego” rozwiązania, które zamyka temat. Skuteczna ochrona formularzy i strony opiera się na kilku warstwach, wdrażanych przed wysłaniem danych, w trakcie ich przetwarzania oraz po stronie serwera.

  1. Zabezpieczenia na poziomie przeglądarki (walidacja danych)
    To najbardziej podstawowa warstwa ochrony.
    Walidacja pól formularza (np. niedozwolone znaki, wymagane formaty, długości pól) pozwala odsiać część błędnych lub przypadkowych danych jeszcze zanim trafią one dalej.

    Ten poziom nie zatrzyma zdeterminowanego ataku, ale:
    • ogranicza „śmieciowe” zgłoszenia,
    • poprawia jakość danych,
    • zmniejsza liczbę prostych błędów użytkowników.
  2. Sprawdzenie po stronie JavaScript
    Kolejny krok przed wysyłką danych. Może pomóc w sytuacjach, gdy problem nie wynika bezpośrednio z ataku na serwer, ale np. z zainfekowanej przeglądarki lub rozszerzeń użytkownika.
    To nadal nie jest warstwa krytyczna, ale dokłada kolejną przeszkodę, którą trzeba ominąć.
  3. Ochrona przed automatyczną wysyłką
    Mechanizmy (które nie eliminują ryzyka w 100%, ale znacząco zmniejszają skalę problemu i obciążenie systemu) takie jak:
    • captcha,
    • honeypot,
    • ograniczenia liczby wysyłek (rate limiting), pozwalają skutecznie zredukować ruch generowany przez boty.
  4. Najważniejsze: walidacja i oczyszczanie danych po stronie serwera
    W opisywanym przypadku to właśnie brak kontroli na tym poziomie otworzył drogę do dalszych problemów. To kluczowy element całego procesu. Niezależnie od tego, co wydarzy się po stronie przeglądarki, serwer:
    • musi traktować każde dane jako potencjalnie niebezpieczne,
    • powinien je sprawdzić, oczyścić i przetworzyć w kontrolowany sposób,
    • nie może ufać temu, co „przyszło z formularza”.
  5. Monitoring i aktualizacje
    Po wdrożeniu zabezpieczeń praca się nie kończy.
    Monitoring oraz regularne aktualizacje to elementy, które pozwalają:
    • wykrywać nietypowe zachowania,
    • reagować zanim problem eskaluje,
    • utrzymać spójność całego systemu.

A jak zabezpieczać samą stronę?

Formularze są tylko jednym z punktów styku z użytkownikiem.
Równie istotna jest higiena całego ekosystemu WordPressa:

  • regularne aktualizacje wtyczek i szablonów,
  • okresowe przeglądy kodu,
  • usuwanie nieużywanych elementów,
  • kontrola tego, co faktycznie działa na serwerze.

Popularność WordPressa sprawia, że jest on częstym celem zautomatyzowanych ataków, które nie są personalne – trafiają tam, gdzie coś się uda. Dlatego bezpieczeństwo nie powinno być jednorazowym działaniem „po problemie”, ale cyklicznym procesem, dokładnie tak jak w przypadku formularzy.

Ilustrowana osoba w żółtym kasku i okularach przeciwsłonecznych siedzi ze skrzyżowanymi nogami z laptopem oznaczonym literą D. Obok znajduje się duża żółta tarcza z projektem sieci i logo OpenAI pośrodku.

Wnioski po incydencie: co sprawdzać i czy vibe coding jest zły?

Coraz częściej spotykam się z tzw. vibe codingiem – szybkim tworzeniem fragmentów kodu metodą prób i błędów, często wspieranym narzędziami AI. W wielu prostych przypadkach takie podejście faktycznie potrafi „zadziałać”. Problem zaczyna się tam, gdzie w grę wchodzą formularze, dane użytkowników i bezpośredni kontakt z serwerem.

To jest moment, w którym kończy się improwizacja, a zaczynają się konsekwencje.

Kod, który „działa”, nie zawsze jest kodem:

  • bezpiecznym,
  • odpornym na automatyczne ataki,
  • dopasowanym do środowiska WordPressa lub innego CMS-a,
  • neutralnym dla stabilności i reputacji całej strony.

Dlatego problemem nie jest sam vibe coding ani wykorzystanie AI. Problemem jest brak procesu. Pisanie kodu to tylko fragment pracy programistycznej. Równie ważne są:

  • zrozumienie architektury systemu,
  • świadomość sposobu działania serwera i interpreterów,
  • znajomość typowych wektorów ataku,
  • testowanie i utrzymanie wdrożonych rozwiązań.

Bez tej wiedzy nawet pozornie niewinny fragment kodu może stać się punktem zaczepienia do dużo poważniejszych problemów - dokładnie tak, jak w opisanym przypadku.

W ostatnim czasie często słychać hasła o tym, że programiści zostaną zastąpieni, a kod „będzie się pisał sam”. Poza sloganami istnieje jednak rzeczywistość operacyjna. A ta jest prosta: ktoś nadal musi rozumieć, co trafia na produkcję i jakie niesie to skutki. Gdy tego zabraknie, konsekwencje przestają być teoretyczne a stają się kosztowne, stresujące i trudne do cofnięcia.


Kiedy warto sprawdzić stronę, zanim pojawi się problem.

Jeśli na Twojej stronie pojawiają się własne skrypty, niestandardowe formularze albo fragmenty kodu dodawane „bo działa”, to zwykle najlepszy moment na audyt jest zanim pojawi się incydent.

Krótka analiza struktury, sposobu przetwarzania danych i punktów styku z serwerem pozwala wychwycić problemy, które na co dzień są niewidoczne. Te, które po ataku generują największe koszty i chaos.

W praktyce takie sprawdzenie nie polega na „szukaniu dziury w całym”, ale na uporządkowaniu tego, co już istnieje, i wskazaniu miejsc wymagających korekty. Dla wielu firm to tańsza i spokojniejsza droga niż odzyskiwanie strony w momencie, gdy przestaje ona spełniać swoje cele marketingowe i sprzedażowe.

Jeśli chcesz spojrzeć na swoją stronę w ten sposób (bez straszenia), z naciskiem na realne ryzyko i priorytety, warto zacząć od rozmowy i krótkiego przeglądu technicznego.

FAQ

Skąd mam wiedzieć, że moja strona WordPress została zaatakowana?

Atak nie zawsze daje widoczne objawy. Często pierwszym sygnałem są spadki zapytań z formularzy, problemy z kampaniami reklamowymi, nietypowe zachowanie strony lub alerty z hostingu. Czasami tak jak w tym wypadku strona zostanie zablokowana na serwerze a powiadomienie otrzymasz przez email.

Czy samo usunięcie wirusa rozwiązuje problem?

Nie zawsze. Usunięcie malware to tylko jeden etap. Jeśli nie zostanie znaleziona i usunięta przyczyna ataku (np. własny skrypt lub formularz), problem może wrócić bo strona znajdzie się na liście podatnych do ataków i będą one kontynuowane.

Czy kod generowany przez AI jest bezpieczny?

AI samo w sobie nie jest ani bezpieczne, ani niebezpieczne. Ryzyko pojawia się wtedy, gdy kod trafia na produkcję bez przeglądu, testów i świadomości konsekwencji jego działania. Tak jak w tym wypadku sam formularz wydawał się ok bo działał ale mógł on być elemetem wejścia do różnego typu ataków jak na przykład:

  • log poisoning
  • header injection
  • overflow itp
Adam Anlauf
Adam Anlauf

CEO

O autorze.

Od lat związany z szeroko rozumianą informatyką. Pierwszą stronę stworzyłem w liceum, za co otrzymałem wyróżnienie.

Ciągle uczę się, aby dorównać tempu rozwoju nowoczesnych technologii łącząc je z wiedzą o psychologii aby zwiększać skuteczność stron i aplikacji internetowych.