Strona klienta przez miesiąc serwowała spam do Google. Człowiek widział pustą stronę

W sierpniu o 9:25 przyszedł mail z pytaniem, które brzmiało niewinnie: „ktoś usunął stronę?”. Strona jednego z klientów, mała firma, zwykły WordPress na naszym serwerze. W przeglądarce zamiast oferty wisiała domyślna strona panelu hostingowego, taka, jaką widzisz na świeżo postawionym serwerze, zanim ktokolwiek cokolwiek wgra. Wyglądało to na awarię albo na czyjś błąd przy porządkach. Nie było ani jednym, ani drugim.

Ten sam adres, odpytany tak, jak odpytuje go robot Google, zwracał 152 kilobajty treści. Buty wojskowe po portugalsku, karty kolekcjonerskie, setki linków. Przeglądarka dostawała 1451 bajtów pustki. Strona przez ponad miesiąc prowadziła podwójne życie: dla ludzi była martwa, dla wyszukiwarki była ruchliwym sklepem ze spamem. Prowadzę agencję AI i automatyzacji dla MŚP i dbamy o kilkadziesiąt stron klientów. Opowiem, jak to wykryliśmy, dlaczego właściciel firmy praktycznie nie ma szans zobaczyć tego sam i co możesz sprawdzić u siebie w pięć minut, zanim zrobi to za ciebie ktoś inny.

Spis treści

Czym właściwie jest cloaking?

Wyobraź sobie sklep, który ma dwie witryny. Jedną od ulicy, dla przechodniów, i drugą od zaplecza, widoczną tylko dla inspektora, który przychodzi raz na jakiś czas sprawdzić, co sklep sprzedaje. Przechodzień widzi pustą półkę z kartką „remont”. Inspektor widzi tysiące produktów, cenniki i strzałki „kup tutaj”. Ten sam adres, ten sam szyld, dwie rzeczywistości. Cloaking to dokładnie to, tylko w internecie: serwer sprawdza, kto pyta, i dla każdego przygotowuje inną odpowiedź.

Jak serwer rozpoznaje, kto pyta? Każda przeglądarka i każdy robot przedstawia się przy wejściu krótkim podpisem, tak zwanym User-Agentem. Chrome mówi „jestem Chrome na Windowsie”, robot Google mówi „jestem Googlebot”. Lepsze odmiany cloakingu dodatkowo sprawdzają adres IP, bo Google odwiedza strony z własnych, znanych puli adresów. W naszym przypadku wystarczał sam podpis. Atakujący dopisał do konfiguracji serwera kilka linijek, które mówiły mniej więcej tak: jeśli przedstawia się robot wyszukiwarki, pokaż mu spam; jeśli człowiek, pokaż mu cokolwiek nudnego.

Jeśli pracujesz z modelami językowymi, znasz pewnie pokrewne zjawisko, o którym od niedawna głośno w badaniach nad bezpieczeństwem AI: model, który zachowuje się inaczej, kiedy „wie”, że jest testowany, a inaczej na co dzień. Cloaking to ten sam pomysł w starszym, prostszym wydaniu. System rozpoznaje egzaminatora i gra przed nim inną rolę niż przed zwykłym użytkownikiem. Problem jest zawsze ten sam: jeśli sprawdzasz system tylko z jednej perspektywy, widzisz tylko jedną z jego twarzy.

Google traktuje cloaking jako jedno z najpoważniejszych naruszeń swoich zasad dotyczących spamu. I słusznie, bo cały sens wyszukiwarki opiera się na założeniu, że robot widzi to samo, co później zobaczy człowiek, który kliknie wynik. Strona, która to założenie łamie, oszukuje obie strony naraz.

Dlaczego właściciel strony niczego nie widzi?

Bo patrzy na nią jako człowiek. To brzmi banalnie, ale to jest sedno całej sprawy i powód, dla którego takie infekcje potrafią żyć tygodniami.

Pomyśl, jak wygląda kontakt właściciela małej firmy z własną stroną. Wchodzi na nią rzadko, zwykle wtedy, gdy trzeba coś poprawić w ofercie albo gdy ktoś z rodziny zapyta „a macie stronę?”. Wpisuje adres w przeglądarkę, widzi coś, zamyka. Nie sprawdza, co widzi Google, bo nikt mu nigdy nie powiedział, że Google może widzieć coś innego. Dlaczego miałby? To ta sama strona.

W naszym przypadku było jeszcze ciekawiej. Atakujący nie podsuwał ludziom ładnej kopii prawdziwej strony, tylko domyślną stronę panelu. Ktoś mógłby powiedzieć, że to głupie z jego strony, bo pusta strona rzuca się w oczy. Tylko że rzuca się w oczy komuś, kto akurat patrzy. Szczerze? Nie wiem, od kiedy dokładnie przeglądarka widziała pustkę, bo z logów nie da się tego odtworzyć. Wiem natomiast, że robot Google od tygodni dostawał coś zupełnie innego, a sygnał alarmowy przyszedł nie od narzędzia, tylko od człowieka, który zajrzał na stronę i zdziwił się, że jej nie ma.

Jest jeszcze druga warstwa ślepoty. Kiedy spróbujesz zalogować się do panelu WordPressa, dostaniesz błąd. Naturalny odruch: „strona się zepsuła, trzeba zadzwonić do informatyka”. W tym przypadku błąd nie wynikał z uszkodzenia. Atakujący zablokował wykonywanie wszystkich plików PHP na stronie poza własną krótką listą. Panel administracyjny przestał działać, bo przestał być potrzebny komukolwiek poza nim. Taka blokada przy okazji chroni infekcję przed konkurencją, czyli przed innymi włamywaczami, i przed skanerami bezpieczeństwa, które próbują uruchomić coś na stronie. Pomysłowe. I dość przerażające, kiedy uświadomisz sobie, że „nie działa logowanie” w małej firmie często czeka na naprawę tydzień albo dwa.

Monitoring „czy strona żyje” też nic tu nie pomoże

Wiele firm ma prosty monitoring dostępności: co kilka minut automat sprawdza, czy strona odpowiada. U nas taki też działał. Tylko że strona odpowiadała. Serwer zwracał kod 200, czyli „wszystko w porządku”, i jakąś treść. Monitoring, który pyta „czy żyjesz?”, dostaje odpowiedź „żyję” i jest zadowolony. Nie pyta „co pokazujesz?”, a już na pewno nie pyta „co pokazujesz komuś innemu niż mnie?”. Pisałem niedawno o tym, że zadanie zakończone sukcesem potrafi niczego nie zrobić. Tu mieliśmy lustrzane odbicie: strona zgłaszała sukces, a robiła coś zupełnie innego, niż powinna.

Jak to wykryliśmy i ile to trwało?

Zgłoszenie przyszło od naszej koleżanki z zespołu, która prowadzi sprawy klientów. Zrobiła coś, czego większość ludzi w tej sytuacji nie robi: zanim napisała, sprawdziła stronę z zewnątrz na dwa sposoby. Jako przeglądarka i jako robot. Dostała dwie różne odpowiedzi i w mailu podała ich rozmiar. Diagnoza z zewnątrz, bez dostępu do serwera, była trafna co do joty: to nie usunięcie strony, to cloaking.

I tu muszę przyznać rzecz, która nie przynosi mi chwały. To zgłoszenie leżało dziewięć godzin, zanim ktoś się nim zajął. Nie dlatego, że ktoś je zlekceważył świadomie, tylko dlatego, że w natłoku spraw wyglądało jak kolejne „coś nie działa na stronie” - a takie sprawy w naturalny sposób spadają w kolejce niżej niż awaria poczty czy serwera. Dziewięć godzin przy infekcji, która trwała już ponad miesiąc, niewiele zmieniło w skali szkód. Ale zmieniło moje podejście: zgłoszenie, w którym ktoś podaje dwie różne liczby dla tego samego adresu, nie jest „czymś na stronie”. Jest incydentem bezpieczeństwa.

Kiedy weszliśmy na serwer, zaczęło się układać w obraz. Plik konfiguracyjny, który sterował cloakingiem, miał datę 3 lipca. Kopie zapasowe pozwoliły ustalić okno włamania na 2 - 22 lipca: kopia z 2 lipca była jeszcze czysta, w kolejnych tygodniach przybywało obcych plików. Odcięliśmy stronę 10 sierpnia. Licząc od pliku z 3 lipca, robot Google był karmiony spamem przez ponad pięć tygodni. Z daty pliku nie wyciągałem jednak wniosków na ślepo, bo daty w systemie plików da się dowolnie cofać - o tym, jak ustalam prawdziwą chronologię włamania, pisałem osobno. Tu daty z plików zgadzały się z tym, co pokazały kopie, więc mogłem im zaufać.

Skala, której nikt się nie spodziewał

Najbardziej zaskoczyły mnie logi. Serwer trzymał je tylko przez 11 dni, więc widziałem wąskie okienko, od końca lipca do dnia odcięcia. W tym okienku robot Google pobrał adresy spamowe ze strony 1 113 410 razy. Unikalnych adresów było 993 752. Prawie milion stron, które w oczach Google należały do małej polskiej firmy, a których ta firma nigdy nie stworzyła i nigdy nie widziała.

Dla porównania: robot Binga zajrzał w tym samym czasie niecałe dwa tysiące razy, Yandex 23 razy. Atakującemu chodziło o Google i Google dostał niemal całą uwagę.

Milion adresów to nie jest liczba, którą da się „posprzątać ręcznie”. To osobny problem, który dostał osobny tekst, bo usuwanie śmieci z indeksu rządzi się własnymi, nieintuicyjnymi zasadami.

Jedno polecenie, które rozstrzyga sprawę

Najprostszy test na cloaking to poprosić serwer o tę samą stronę dwa razy: raz jako zwykła przeglądarka, raz podając się za robota Google. Jeśli odpowiedzi różnią się drastycznie, masz problem. Narzędzie, które to robi, nazywa się curl i jest wbudowane w każdy współczesny Windows, Maca i Linuksa. Otwierasz wiersz poleceń i wpisujesz dwa polecenia:

curl -s -o NUL -w "%{size_download}\n" https://twoja-strona.pl/
curl -s -o NUL -w "%{size_download}\n" -A "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" https://twoja-strona.pl/

Każde z nich wypisze jedną liczbę: ile bajtów serwer odesłał. Na Macu i Linuksie zamiast `NUL` wpisz `/dev/null`. U nas pierwsza liczba wynosiła 1451, druga ponad 150 tysięcy. Taka różnica nie wymaga interpretacji. Zdrowa strona da w obu przypadkach liczby bardzo zbliżone - drobne różnice biorą się z dynamicznych elementów, ale nie stukrotne.

Dlaczego ten test nie zawsze wystarczy

Tu uczciwe zastrzeżenie. Nasz przypadek był prosty, bo atakujący rozpoznawał robota wyłącznie po podpisie. Bardziej wyrafinowane infekcje sprawdzają też, czy zapytanie naprawdę przyszło z adresów Google. Wtedy twój curl z laptopa, nawet podpisany jako Googlebot, dostanie niewinną stronę, bo serwer zobaczy, że adres IP się nie zgadza. Wynik „liczby są równe” oznacza więc „nie widać prostego cloakingu”, a nie „strona jest czysta”.

Na tę bardziej podstępną wersję jest narzędzie od samego Google. W Google Search Console, w zakładce sprawdzania adresu URL, możesz poprosić o test na żywo. Wtedy stronę pobiera prawdziwy robot Google, z prawdziwych adresów Google, i pokazuje ci, co zobaczył. To jest najbliżej prawdy, jak się da. Jeśli nie masz podpiętej Search Console do swojej strony, to szczerze - podepnij ją dzisiaj, niezależnie od tego tekstu. To darmowe, a Google wysyła tamtędy ostrzeżenia o problemach z bezpieczeństwem.

Trzeci, najprostszy sygnał nie wymaga żadnych narzędzi. Wpisz w Google `site:twoja-strona.pl` i przejrzyj kilka stron wyników. Jeśli widzisz tytuły w obcych językach, produkty, których nie sprzedajesz, albo dziwne adresy z długimi ciągami cyfr, wiesz już wszystko. W naszym przypadku adresy spamowe miały postać strony głównej z doklejonym parametrem i liczbą. Prawie milion wariantów tej samej końcówki.

Co atakujący z tego ma, a co traci firma?

Często słyszę: „przecież moja strona jest mała, kto by się na nią włamywał?”. To pytanie zakłada, że włamywacz chce czegoś od ciebie. Nie chce. Chce twojej domeny.

Stara domena małej firmy ma w oczach Google pewną historię i wiarygodność. Działa od lat, nikt na niej nie spamował, linkują do niej lokalne katalogi i kontrahenci. Dla kogoś, kto chce wypromować w wyszukiwarce sklep z podróbkami albo podejrzane strony, taka domena jest jak czyste konto bankowe dla kogoś, kto pierze pieniądze. Przez nie można przepuścić ruch, który z nowej domeny od razu zostałby rozpoznany. Atakujący generuje na twojej domenie setki tysięcy podstron, karmi nimi robota i liczy, że część trafi do wyników wyszukiwania i przekieruje ludzi tam, gdzie on chce.

Cloaking jest tu ochroną inwestycji. Gdyby ludzie widzieli spam, właściciel zauważyłby to w godzinę. Pokazując ludziom coś nudnego, atakujący kupuje sobie tygodnie.

Rachunek po stronie firmy

Co traci właściciel? Lista jest dłuższa, niż się wydaje:

  • pozycję w wyszukiwarce - Google, który wykryje cloaking, może obniżyć widoczność całej domeny albo usunąć ją z wyników, a odbudowa zaufania trwa miesiącami
  • pieniądze na sprzątanie - przy tej infekcji wycena samego czyszczenia wyszła na kilka tysięcy złotych, do tego aktualizacja i porządne kopie
  • wiarygodność - klient, który wpisze nazwę firmy w Google i zobaczy wyniki z butami wojskowymi po portugalsku, nie pomyśli „biedni, włamali im się”, tylko „coś tu jest nie tak”
  • czas - na wyjaśnianie, zgłaszanie, odpowiadanie na pytania, dlaczego strona przez tydzień była w przerwie technicznej

Jest też koszt, o którym mało kto myśli. Dziś stronę firmy czyta nie tylko Google, ale coraz częściej asystenci AI, którzy odpowiadają ludziom na pytania o firmy i produkty. Nie mam dowodu, że w tym przypadku spam trafił do któregoś z modeli językowych. Ale zasada jest prosta: jeśli ktoś podsuwa robotom inną treść niż ludziom, to każdy robot, także ten od asystenta AI, może dostać tę gorszą wersję. O tym, co internet mówi o twojej firmie, zanim zadzwoni klient, pisałem przy okazji audytu marki. Cloaking to najgorszy możliwy scenariusz tego audytu: internet mówi o tobie rzeczy, których sam nigdy nie zobaczysz.

Jak zatrzymaliśmy ruch, nie niszcząc dowodów?

Pierwszy odruch przy takim znalezisku jest prosty: skasować. Wywalić zainfekowane pliki, przywrócić stronę, zapomnieć. Ten odruch jest zły z dwóch powodów. Po pierwsze, kasując na oślep, nie wiesz, co przeoczyłeś, a infekcje tego typu lubią się odradzać z miejsc, o których nie pomyślałeś. Po drugie, kasujesz materiał, z którego dałoby się ustalić, jak atakujący wszedł i co jeszcze zrobił.

Zrobiliśmy to w innej kolejności. Najpierw pełna kopia katalogu strony, około 1,4 GB, i osobno baza danych. Obie sprawdzone odczytem, nie tylko „skopiowane bez błędu” - kopia, której nikt nie otworzył, nie jest kopią, a tu od niej zależało całe dalsze śledztwo. Dopiero potem odcięcie.

Odcięcie nie polegało na usunięciu czegokolwiek. Przestawiliśmy w konfiguracji serwera katalog, z którego strona jest serwowana, na osobny, z prostą stroną przerwy technicznej. Jedna linijka konfiguracji. Ruch zatrzymał się w minutę, zarówno dla ludzi, jak i dla robotów. Zainfekowane pliki leżały dalej nietknięte, gotowe do analizy. Gdyby się okazało, że coś pomyliliśmy, cofnięcie zajęłoby kolejną minutę. Na tym samym serwerze działały dziesiątki innych stron i żadna nie odczuła przerwy, bo serwer przeładowaliśmy łagodnie, bez zrywania połączeń.

Drugi krok dotyczył Google. Adresom spamowym ustawiliśmy odpowiedź „410 - usunięto na stałe”. To komunikat dla robota: tej strony nie ma i nie będzie, wyrzuć ją z indeksu. Po wszystkim sprawdziliśmy z zewnątrz tym samym poleceniem co na początku. Przeglądarka i robot dostały identyczne 658 bajtów. Cloaking był martwy.

Czego nie robić przy sprzątaniu indeksu

Jedna rzecz, na której sam się prawie przewróciłem, zasługuje na osobne ostrzeżenie. Odruchowo wpisałem w pliku robots.txt blokadę dla wszystkich robotów, żeby odciąć Google od spamu. Po minucie to cofnąłem. Robot, któremu zabronisz wejścia, nie odwiedzi adresu, więc nigdy nie zobaczy komunikatu „410 - usunięto”. A skoro go nie zobaczy, wpis zostanie w wynikach. Blokada w robots.txt w takiej sytuacji nie sprząta spamu, tylko go konserwuje. Więcej o tym w osobnym tekście o czyszczeniu indeksu, bo to temat na kilka stron.

Gdzie się pomyliłem?

Obiecałem sobie, że na tym blogu będę pisał też o własnych błędach, więc proszę bardzo. W tej sprawie były trzy.

Pierwszy już znasz: zgłoszenie czekało dziewięć godzin, bo zostało potraktowane jak drobna usterka strony. Dziś każde zgłoszenie typu „strona wygląda inaczej niż powinna” traktujemy jak potencjalny incydent, dopóki nie wykluczymy, że nim jest.

Drugi był poważniejszy. Tego samego dnia przejrzałem pozostałe strony na serwerze i napisałem w raporcie, że zainfekowana była tylko ta jedna. Wniosek opierał się na tym, że sprawdziłem nazwy plików i daty ich modyfikacji w głównych katalogach stron. Trzy dni później, przy dokładniejszym przeglądzie, okazało się, że to za mało. Infekcje tego typu chowają się w katalogach, które WordPress ładuje automatycznie, i w kontach administratorów dopisanych do bazy danych. Zajęte były też dwie inne strony. Sprostowałem raport, ale przez trzy dni klienci i zespół żyli w przekonaniu, które nie było prawdą. Było mi z tym naprawdę źle - bo „sprawdziłem, czysto” to zdanie, na którym ludzie budują decyzje.

Trzeci błąd był strukturalny i nie mój osobiście, tylko nasz jako operatora serwera. Logi serwera WWW trzymały się 10 - 11 dni. Włamanie z początku lipca było daleko poza tym zasięgiem, więc z logów nie dało się ustalić, jak atakujący wszedł. Mogliśmy tylko zgadywać. Retencja logów to jedna z tych nudnych decyzji konfiguracyjnych, które podejmuje się raz, przy instalacji, i zapomina. Dopóki nie trzeba niczego wyjaśnić.

Jest jeszcze jedno spostrzeżenie, które nie jest błędem, ale daje do myślenia. Strony, którymi opiekowaliśmy się na stałe, w ramach stałej umowy z aktualizacjami i przeglądami, były czyste. Zajęte zostały te, które latami działały „same”, bo nikt nie zamówił opieki. Nie piszę tego, żeby coś sprzedać. Piszę, bo to najtwardszy dowód, jaki mam, na to, że regularne aktualizacje WordPressa to nie jest fanaberia informatyka.

Co sprawdzić u siebie jeszcze dziś?

Jeśli masz firmową stronę na WordPressie, a w małych i średnich firmach w Polsce to wciąż najczęstszy wybór, oto krótka lista. Pierwsze trzy punkty zrobisz sam w kwadrans, bez żadnej wiedzy technicznej.

Pięć minut, bez informatyka

  • Wpisz w Google `site:` i swoją domenę. Przejrzyj trzy, cztery strony wyników. Obce języki, produkty, których nie sprzedajesz, dziwne adresy - wszystko to jest sygnał.
  • Porównaj stronę oczami człowieka i robota. Dwa polecenia curl z tego tekstu. Jeśli liczby różnią się wielokrotnie, dzwoń do kogoś, kto się na tym zna.
  • Sprawdź, czy masz Google Search Console. Jeśli nie, podepnij. Jeśli tak, zajrzyj do sekcji o problemach z bezpieczeństwem i działaniach ręcznych.

Do zlecenia komuś, kto prowadzi ci stronę

  • Lista kont administratorów. Ile ich jest i czy każde potrafisz przypisać do konkretnej osoby. Konto „admin2”, którego nikt nie zakładał, to nie przypadek.
  • Aktualizacje. WordPress, wtyczki, motyw. Kiedy ostatnio? Jeśli odpowiedź brzmi „nie wiem”, odpowiedź brzmi „dawno”.
  • Kopie zapasowe, sprawdzone odtworzeniem. Nie „robią się”, tylko „ostatnio odtworzyliśmy z nich plik i działało”. To kopia sprzed infekcji pozwoliła nam ustalić okno włamania i plan sprzątania.
  • Retencja logów. Ile dni serwer trzyma dzienniki. Jeśli tydzień, to włamanie sprzed miesiąca będzie zagadką bez rozwiązania.

Monitoring, który pyta o treść, nie tylko o życie

Jeśli masz już monitoring dostępności, dołóż do niego jedno pytanie: czy robot i przeglądarka dostają podobną odpowiedź. Technicznie to dwa zapytania zamiast jednego i porównanie rozmiaru, czyli kilka linijek dla kogoś, kto i tak utrzymuje ci monitoring. To jest dokładnie ta lekcja, którą wyniosłem z całej sprawy. Nie wystarczy sprawdzać, czy system żyje. Trzeba sprawdzać, czy wszystkim mówi to samo.

Ta zasada działa zresztą daleko poza stronami WWW. Każdy system, który ocenia się tylko z jednej perspektywy, ma szansę pokazać ci jedną twarz, a światu drugą. Agent AI, który dobrze wypada w testach, a gorzej w rozmowie z klientem. Raport, który wygląda świetnie dla zarządu, a dla księgowej nie trzyma się kupy. Strona, która dla właściciela jest pusta, a dla Google jest sklepem ze spamem. Wszędzie pomaga to samo: zapytaj drugi raz, z innej strony, i porównaj.

Słownik pojęć

  • Cloaking - technika, w której serwer pokazuje robotom wyszukiwarki inną treść niż ludziom. Google uznaje ją za poważne naruszenie swoich zasad dotyczących spamu.
  • Googlebot - robot Google, który odwiedza strony i pobiera ich treść do indeksu wyszukiwarki.
  • User-Agent - krótki podpis, którym przeglądarka albo robot przedstawia się serwerowi przy każdym zapytaniu. Łatwy do podrobienia w obie strony.
  • curl - darmowe narzędzie wiersza poleceń do pobierania stron i plików. Pozwala podać dowolny User-Agent i sprawdzić, co serwer odsyła.
  • Kod 410 - odpowiedź serwera „usunięto na stałe”. Dla robota wyszukiwarki to sygnał, żeby wyrzucić adres z indeksu.
  • robots.txt - plik z instrukcjami dla robotów, gdzie wolno im wchodzić. Blokada w nim nie usuwa stron z wyników, tylko zabrania robotowi je odwiedzać.
  • Google Search Console - darmowe narzędzie Google dla właścicieli stron. Pokazuje, jak Google widzi stronę, i ostrzega o problemach z bezpieczeństwem.
  • Retencja logów - czas, przez jaki serwer przechowuje dzienniki zdarzeń. Po jego upływie ślady są kasowane.

Nie wiesz, co twoja strona pokazuje robotom?

Jeśli po przeczytaniu tego tekstu wpisałeś `site:` i zobaczyłeś coś, czego nie rozumiesz, albo curl zwrócił dwie bardzo różne liczby, napisz do mnie na [email protected]. Wyślij adres strony i oba wyniki. Powiem ci wprost, czy to powód do niepokoju, a jeśli tak, od czego zacząć, żeby nie skasować przy okazji dowodów, które przydadzą się później.

✓ Sprawdzone na
własnej firmie
cybulski.ai JC
You've successfully subscribed to cybulski.ai
Great! Next, complete checkout for full access to cybulski.ai
Welcome back! You've successfully signed in.
Unable to sign you in. Please try again.
Success! Your account is fully activated, you now have access to all content.
Error! Stripe checkout failed.
Success! Your billing info is updated.
Error! Billing info update failed.