Problem spamu w formularzach
Formularz kontaktowy na stronie internetowej to zaproszenie do komunikacji — niestety nie tylko dla potencjalnych klientów. Boty spamowe systematycznie skanują internet w poszukiwaniu formularzy, wysyłając przez nie reklamy, phishing i złośliwe linki. Niezabezpieczony formularz może generować setki niechcianych wiadomości dziennie, utrudniając dotarcie do prawdziwych zapytań.
Jak skutecznie ograniczyć spam bez utrudniania życia użytkownikom? Istnieje kilka sprawdzonych technik, które można łączyć ze sobą dla najlepszego efektu.
Honeypot — pułapka na boty
Honeypot to jedna z najelegantszych metod walki ze spamem. Polega na dodaniu do formularza ukrytego pola, które jest niewidoczne dla użytkownika, ale widoczne dla bota.
Implementacja jest prosta:
<div style="position: absolute; left: -9999px;">
<label for="website">Nie wypełniaj tego pola</label>
<input type="text" name="website" id="website" tabindex="-1" autocomplete="off">
</div>
Na serwerze sprawdzamy, czy pole honeypot zostało wypełnione:
if r.FormValue("website") != "" {
// To bot — ignorujemy zgłoszenie
http.Redirect(w, r, "/kontakt/dziekujemy", http.StatusSeeOther)
return
}
Kluczowe jest, aby po wykryciu bota nie pokazywać błędu — bot powinien myśleć, że wiadomość została wysłana pomyślnie. W przeciwnym razie autorzy botów dostosują je do omijania zabezpieczenia.
Skuteczność honeypota szacuje się na 90-95% prostych botów. Jest to metoda całkowicie przezroczysta dla użytkownika — nie wymaga żadnej dodatkowej interakcji.
Rate limiting — ograniczenie częstotliwości
Rate limiting polega na ograniczeniu liczby zgłoszeń z jednego adresu IP w określonym czasie. Nawet jeśli bot przejdzie przez inne zabezpieczenia, nie będzie w stanie wysłać setek wiadomości.
Implementacja w Go z użyciem mapy i muteksu:
var (
submissions = make(map[string]time.Time)
mu sync.Mutex
)
func rateLimitCheck(ip string) bool {
mu.Lock()
defer mu.Unlock()
last, exists := submissions[ip]
if exists && time.Since(last) < 60*time.Second {
return false // za częste wysyłanie
}
submissions[ip] = time.Now()
return true
}
Rozsądny limit to 1 wiadomość na 60 sekund z jednego IP. Dla większości formularzy kontaktowych to wystarczający margines — użytkownik rzadko wysyła dwie wiadomości pod rząd.
Na poziomie serwera HTTP (np. Nginx) warto dodatkowo skonfigurować globalny rate limiting dla endpointu formularza:
limit_req_zone $binary_remote_addr zone=contact:10m rate=1r/m;
location /kontakt {
limit_req zone=contact burst=2 nodelay;
}
Walidacja czasu wypełnienia
Boty wypełniają formularze niemal natychmiastowo — w ułamku sekundy. Człowiek potrzebuje co najmniej kilku sekund na wpisanie imienia, adresu email i treści wiadomości.
Technika polega na zapisaniu znacznika czasu przy renderowaniu formularza i sprawdzeniu, ile czasu upłynęło do momentu wysłania:
<input type="hidden" name="ts" value="1693742400">
Na serwerze weryfikujemy:
ts, _ := strconv.ParseInt(r.FormValue("ts"), 10, 64)
elapsed := time.Now().Unix() - ts
if elapsed < 3 {
// Zbyt szybko — prawdopodobnie bot
return
}
Formularz wypełniony w mniej niż 3 sekundy jest niemal na pewno dziełem bota.
Alternatywy dla tradycyjnej CAPTCHA
Klasyczny CAPTCHA z rozpoznawaniem liter jest skuteczny, ale frustrujący dla użytkowników. Nowoczesne alternatywy oferują lepsze doświadczenie:
Turnstile (Cloudflare) — darmowa usługa, która w większości przypadków nie wymaga żadnej interakcji od użytkownika. Weryfikacja odbywa się w tle na podstawie analizy behawioralnej. Integracja wymaga jedynie dodania widgetu JavaScript i weryfikacji tokenu po stronie serwera.
hCaptcha — alternatywa dla Google reCAPTCHA, z lepszą polityką prywatności. Oferuje tryb pasywny podobny do Turnstile.
Proste pytanie logiczne — np. "Ile to 2 + 3?" lub "Jaki jest dzisiejszy dzień tygodnia?". Skuteczne przeciwko prostym botom, ale łatwe do obejścia przez zaawansowane skrypty.
Walidacja po stronie serwera
Niezależnie od zastosowanych technik antyspamowych, walidacja danych wejściowych jest obowiązkowa:
- Sanityzacja — usuwanie znaczników HTML i potencjalnie niebezpiecznych znaków
- Sprawdzanie formatu email — odrzucanie niepoprawnych adresów
- Limity długości — ograniczenie długości pól (np. imię: 100 znaków, wiadomość: 5000 znaków)
- Sprawdzanie treści — odrzucanie wiadomości zawierających typowe frazy spamowe lub nadmiarową liczbę linków
Łączenie metod — obrona w głąb
Najskuteczniejsze podejście to łączenie kilku technik jednocześnie. Rekomendowana kombinacja dla typowego formularza kontaktowego:
- Honeypot — pierwszy filtr, eliminuje większość prostych botów
- Walidacja czasu — odrzuca formularze wypełnione zbyt szybko
- Rate limiting — ogranicza częstotliwość wysyłania z jednego IP
- Walidacja danych — sprawdza poprawność i sanityzuje dane wejściowe
Ta kombinacja eliminuje ponad 99% spamu bez jakiegokolwiek utrudnienia dla użytkownika. Dopiero gdy te metody okażą się niewystarczające, warto rozważyć dodanie Turnstile lub innego rozwiązania CAPTCHA.
Podsumowanie
Zabezpieczenie formularza kontaktowego nie musi oznaczać frustrowania użytkowników rozpoznawaniem rozmytych znaków. Honeypot, rate limiting i walidacja czasu to proste techniki, które można zaimplementować w kilkadziesiąt minut, a ich skuteczność jest zaskakująco wysoka. Kluczowe jest stosowanie kilku warstw ochrony jednocześnie — żadna pojedyncza metoda nie jest stuprocentowo skuteczna, ale ich kombinacja tworzy solidną barierę przed niechcianą korespondencją.