Czy prościej znaczy lepiej?

Opublikowano Kategorie PrzemyśleniaCzas czytania 9min

Ile razy w trakcie mojej pracy okazywało się, że „prościej” oznacza „lepiej”? Obawiam się, że zbyt wiele. Po raz kolejny doszedłem do takiego wniosku w trakcie prac nad usprawnieniami na blogu. Zapraszam do lektury nieco luźniejszego tekstu, który może dostarczyć Ci kilku wniosków użytecznych w codziennym programistycznym rzemiośle.

Kontekst

Po uruchomieniu bloga oczywistym must-have była dla mnie sekcja komentarzy i formularz kontaktowy. Dość szybko zauważyłem, że wszelkie miejsca na blogu, w które użytkownik może coś wpisać, stają się celem botów. Tym sposobem w mojej skrzynce odbiorczej oraz w komentarzach do zatwierdzenia każdego dnia lądowały dziesiątki, jeśli nie setki, wiadomości z linkami do kasyn online, leków na potencję i innych serwisów z produktami o wątpliwej reputacji. Szybki research pokazał, że dość skutecznym rozwiązaniem jest połączenie AkismetreCAPTCHA.

Akismet jest narzędziem do detekcji spamu. Ono nie tyle chroni przed nim, ile pozwala stwierdzić czy coś jest spamem. Mechanizmu CAPTCHA, mam nadzieję, nie muszę nikomu przedstawiać. Aby jednak dopełnić formalności, akronim CAPTCHA rozwija się do Completely Automated Public Turing test to tell Computers and Humans Apart. Celem mechanizmu jest powstrzymanie akcji botów na stronie, takich jak wypełnianie formularzy, klikanie przycisków itp. Zwykle odbywa się to przez zadania proste dla człowieka, lecz trudne do wykonania przez komputer. Może to być prosta zagadka, przepisanie tekstu czy rozpoznanie obiektów na obrazkach. Czasami CAPTCHA działa w tle, analizując zachowanie użytkownika.

Wdrożyłem więc oba rozwiązania i problem zniknął. Niestety do czasu. Z początkiem 2025 roku otrzymałem maila, który informował o konieczności migracji reCAPTCHA do Google Cloud. Wczytanie się w warunki zapaliło u mnie kilka lampek ostrzegawczych:

  • muszę mieć konto w GCP ze skonfigurowanym billingiem i podpiętą kartą,
  • darmowy tier obejmuje jedynie 10000 zapytań miesięcznie.

W teorii nie powinienem przekroczyć darmowego limitu, a nawet jeśli to koszt za kolejne 100 000 zapytań to $8. Nie ma tragedii, jednak jeśli każdego miesiąca w skali roku bym przekroczył darmowy limit, mówimy wtedy o kwocie $96. Ochrona przed komentarzami i wiadomościami z reklamami kasyn i oraz plastrów na odchudzanie to nie jest coś, za co chciałbym płacić potencjalnie kilkaset złotych rocznie. W moim przypadku wniosek mógł być tylko jeden — trzeba szukać alternatywy.

Dodatkowym aspektem przemawiającym za migracją jest moja niechęć do korporacyjnych molochów (patrzę na Ciebie Johnny Silverhand) i narastająca od coraz dłuższego czasu chęć stopniowego wycofania się z ekosystemu Google. O ile z YouTube, Gmaila czy Google Docsów ciężko pewnie będzie mi zrezygnować, tak reCAPTCHA zdecydowanie nie należy do usług, bez których nie mógłbym żyć (Google Analytics — jesteście następne w kolejce).

Rozwiązanie – próba nr 1

Pierwsza próba rozwiązania problemu zakładała przesiadkę na Cloudflare Turnstile. Z uwagi na setup bloga i tak jestem uwiązany do Cloudflare, więc wykorzystanie kolejnej usługi z ich portfolio aż tak mnie nie bolało. Dodatkowo usługa jest darmowa, a jak powszechnie wiadomo gratis to uczciwa cena. Samo przepięcie się zajęło może kilka minut. Turnstile nie pokazuje użytkownikowi żadnej zagadki ani zadania do rozwiązania. Właściwie to można go wręcz całkowicie ukryć. Cloudflare podchodzi do tematu w następujący sposób:

Turnstile adapts the challenge outcome to the individual visitor or browser. First, we run a series of small non-interactive JavaScript challenges to gather signals about the visitor or browser environment.

These challenges include proof-of-work, proof-of-space, probing for web APIs, and various other challenges for detecting browser-quirks and human behavior. As a result, we can fine-tune the difficulty of the challenge to the specific request and avoid showing a visual or interactive puzzle to a user.

Jakież było moje zdziwienie, gdy po kilku tygodniach w katalogu „spam” znalazłem kilkaset komentarzy do zatwierdzenia. Zacząłem researchować temat, przekonany, że to ja coś zepsułem. Jednak po sprawdzeniu statystyk okazało się, że Cloudflare ocenił około połowy ruchu na mojej stronie jako „likely bot”. Oznacza to, że rozwiązanie jest uruchomione i skonfigurowane.

Sprawdziłem opcje konfiguracyjne i niewiele to dało. Nie dość, że był ustawiony najbardziej restrykcyjny wariant, który niekiedy wymusza zaznaczenie dodatkowego checkboxa, to jeszcze użytkownik musi rozwiązywać challenge każdorazowo (wyłączona opcja pre-clearance).

Researchując temat, trafiłem na ciekawy wpis na Reddicie. Okazuje się, że nie jestem jedyną osobą, która zauważyła, że coś jest nie tak. Udało mi się nawet znaleźć poradnik, jak efektywnie obejść challenge przygotowany przez Turnstile. To nieco podłamało moją wiarę w skuteczność tej usługi.

Nie zakładam też, by problem leżał w samej integracji Turnstile z modułem komentarzy. Ta sama integracja odpowiada za obsługę formularza kontaktowego i w tym przypadku działa poprawnie. Nie wykluczam jednak, że to ja zrobiłem coś nie tak. Do chwili obecnej nie potrafię odpowiedzieć, czy to ja robię coś nie tak, czy faktycznie problem jest w samej usłudze. Jeśli masz swoje przemyślenia na ten temat, to chętnie dowiem się więcej.

Rozwiązanie – próba nr 2

Brak sukcesu w wykorzystaniu Turnstile sprawiła, że zacząłem rozglądać się za kolejnymi. Pierwsza myśl była taka, by poszukać kolejnej alternatywy dla CAPTCHA. Po dłuższym researchu nie znalazłem jednak nic, co chciałbym przetestować w praktyce. Rozważałem wykorzystanie ALTCHA, jednak ostatecznie zrezygnowałem z tego pomysłu z uwagi na konieczność deploymentu i utrzymania własnego backendu. Rozwiązania opartego na zagadce matematycznej również nie brałem pod uwagę. Nie chcę zmuszać użytkowników do wypełniania niepotrzebnych pól, szczególnie, że reCAPTCHA i Turnstile działały w tle. Brałem również pod uwagę powrót do reCAPTCHA i wywieszenie białej flagi w mojej ucieczce od Google.

Jednak w tym momencie pomyślałem, by zrobić krok wstecz i jeszcze raz przemyśleć faktyczny problem. Moim problemem nie jest konieczność instalacji rozwiązania do CAPTCHY, tylko konieczność pozbycia się spamu od botów. Wpadłem więc na pomysł, by po prostu automatycznie czyścić spam np. codziennie. Ten pomysł ostatecznie odrzuciłem po tym, gdy do spamu przypadkiem wpadł komentarz od czytelnika.

Zabrałem się za dalszy research, mając już nieco inny problem do rozwiązania i tak trafiłem na rozwiązanie genialne w swojej prostocie. Boty wykorzystywane przez spamerów, by działać efektywnie, zwykle są generyczne. Bazują na znanych mechanizmach, narzędziach i interfejsach. Oznacza to, że dowolny niestandardowy mechanizm prawdopodobnie nie zostanie poprawnie obsłużony przez większość z nich.

Rozwiązanie, które jak dotąd całkowicie rozwiązało problem spamu, jest absurdalne w swojej prostocie. Do formularza komentarzy zostało dodane niewidoczne pole. Warunkiem pomyślnego przetworzenia zapytania dodającego komentarz jest obecność tego pola. Drugim warunkiem koniecznym jest to, by to pole było puste. Takie rozwiązanie pozwala wychwycić dwa rodzaje zachowań botów:

  • wyślij w zapytaniu tylko znane mi pola;
  • sprawdź możliwe pola do wypełnienia, podaj wartości we wszystkich i wyślij komentarz.

Rozwiązanie testuję od około miesiąca i w spamie nie pojawił się ani jeden komentarz. Jednocześnie wiem, że dodawanie komentarzy nadal działa — dostałem w tym czasie kilka zwykłych komentarzy. Wdrożenie rozwiązania ogranicza się do dodania prostej akcji i filtra w pliku functions.php.


add_action('comment_form', function () {
    echo '<p style="display:none;"><label>Leave this field empty</label>
        <input type="text" name="hp_comment" value=""></p>';
});

add_filter('preprocess_comment', function ($commentdata) {
    if (!empty($_POST['hp_comment'])) {
        wp_die('Spam!');
    }

    if (!isset($_POST['hp_comment'])) {
        wp_die('Spam!');
    }

    return $commentdata;
});

Czy to rozwiązanie jest idealne? Zdecydowanie nie! Szybkie sprawdzenie kodu HTML strony od razu demaskuje nasz mechanizm. Akceptuję to ryzyko, ponieważ wymaga to więcej zaangażowania niż tylko uruchomienie automatu. Ostatni miesiąc pokazał, że rozwiązanie działa. Jeśli komuś będzie bardzo zależało, to i tak będzie mi wysyłał spam. Szukając analogii — ogrodzenie pod napięciem było zbyt drogie, więc postanowiłem przynajmniej zapiąć bramę na kłódkę. A jak ktoś będzie chciał to i tak przeskoczy.

Wnioski

Wnioski z rozwiązania tego problemu mam dwa. Pierwszy dotyczy pytania, czy prościej znaczy lepiej? Często odpowiedź brzmi tak. Nie jest to absolutnie uniwersalna rada. Trzeba mieć wyczucie, kiedy można pójść na skróty, a kiedy może nas to bardzo zaboleć. Jednak w wielu przypadkach najprostsze rozwiązanie jest wystarczające. Szczególnie wtedy, gdy mówimy o obszarze niekrytycznym w naszym produkcie czy systemie. W opisanym use case to jest właśnie taki przypadek.

Drugi wniosek to taki, że czasami warto zrobić krok wstecz i szerzej spojrzeć na problem. Rozwiązanie go może być w zupełnie innym miejscu, niż pierwotnie go szukaliśmy. Możliwe też, że próbujemy rozwiązać niewłaściwy problem.

Materiały uzupełniające

Dominik Szczepaniak

Zawodowo Senior Software Engineer w CKSource. Prywatnie bloger, fan włoskiej kuchni, dobrej kawy i miłośnik jazdy na rowerze.

Inne wpisy, które mogą Cię zainteresować

Kolejna książka o Gicie — naucz się korzystać z Gita jak profesjonalista

Okładka e-booka - Kolejna książka o Gicie

"Kolejna książka o Gicie" to kompleksowy e-book, który pozwoli Ci poznać Gita od A do Z, a także liczne narzędzia dedykowane pracy z Gitem!

Dlaczego warto?

  • 👉 Git od podstaw do poziomu PRO. E-book przeprowadzi Cię krok po kroku, niezależnie od poziomu doświadczenia.
  • 👉 Zdobędziesz praktyczne umiejętności, które natychmiast wykorzystasz w prawdziwych projektach.
  • 👉 Wiedza połączona z praktyką! Oprócz masy teorii w e-booku znajdziesz też zadania praktyczne.

Okładka e-booka - Kolejna książka o Gicie

Przygotuj się lepiej do rozmowy o pracę!

Odbierz darmowy egzemplarz e-booka 106 Pytań Rekrutacyjnych Junior JavaScript Developer i realnie zwiększ swoje szanse na rozmowie rekrutacyjnej! Będziesz też otrzymywać wartościowe treści i powiadomienia o nowych wpisach na skrzynkę e-mail.

Dlaczego warto?

  • 👉 Ponad 1000 pobrań e-booka!
  • 👉 60 stron pełnych pytań i zadań praktycznych. Pytania i zadania pochodzą z faktycznych procesów rekrutacyjnych.

E-booka odbierzesz korzystając z formularza poniżej 👇

Okładka e-booka - Kolejna książka o Gicie

guest

6 komentarzy
Najwięcej głosów
Najnowsze Najstarsze
Michał
Michał
5 miesiące temu

ciekawy artykuł!

Rob
Rob
5 miesiące temu

Można jeszcze spróbować z hcaptcha

Andrzej Szczepaniak
1 miesiąc temu

Wpis jest z grudnia, a mamy maj.
Odkąd wstawiłem Twoje rozwiązanie to mam zero spamu, totalne zero.
Kod HTML strony pokazuje <label>Leave this field empty</label>, a więc nie zdradza jak to realnie działa.

Tomek
Tomek
5 miesiące temu

Kiedyś mierzyłem się z podobnym problemem, tylko dotyczył on setek stron na wspólnym systemie. Pomyślałem, że połączę kilka metryk zamiast jednej (w tym ukryte pola) i dodatkowo zapisywałem każdą błędną próbę. Okazało się, że większość botów odpadała na weryfikacji czasu od wyświetlenia formularza do jego wysłania (zazwyczaj min. 3 sekundy). Duża część żądań w ogóle nie zawierała ID z sesji, po którym liczyłem czas, więc bot nie wyświetlił strony z formularzem przez jego wysłaniem.