ERETEK
BİLGİ SİSTEMLERİ

Web Formlarında Spam Önleme: Honeypot, Turnstile ve Sunucu Kontrolleri

Form spam önlemede honeypot, imzalı zaman token’ı, Turnstile ve reCAPTCHA, Nginx rate limit, içerik filtreleri ve bildirim e-postasının güvenilir teslimi.

Bu makalede7 bölüm
Teknik özet
Teknoloji
Cloudflare Turnstile, reCAPTCHA, Nginx limit_req, PHP, SPF/DKIM/DMARC, WordPress
Konu
Katmanlı form spam önleme
Seviye
Orta
Ön koşullar
  • Form eklentisi veya form uç noktasına erişim
  • Web sunucusu yapılandırma yetkisi

İletişim ve teklif formlarına düşen spam’in maliyeti gelen kutusunun dolmasından ibaret değil. Satış ekibi gerçek talebi yüzlerce çöp kaydın arasında kaçırır, bildirim e-postaları spam klasörüne düşer, form üzerinden giden otomatik yanıtlar alan adının itibarını yer. Tek bir CAPTCHA eklemek ya yetmez ya da gerçek kullanıcıyı yorar. Aşağıdaki yaklaşım katmanlıdır: görünmez kontrollerle başlar, sunucu tarafı sınırlamayla devam eder ve bildirimin güvenilir teslimiyle biter.

Form spam’inin türleri ve kaynakları

Doğru önlem, spam’in nasıl üretildiğine bağlıdır. Konsolda ilk bakılacak yer form kayıtları ve sunucu erişim günlüğüdür; aynı IP’den saniyeler arayla gelen POST istekleri ile gün boyu dağınık gelen tek tük kayıtlar farklı türlere işaret eder.

Tür Davranış Etkili katman
Basit bot Sayfayı açmadan form uç noktasına doğrudan POST gönderir Honeypot, token, zaman kontrolü
Tarayıcı tabanlı bot Headless tarayıcıyla sayfayı yükler, JavaScript çalıştırır Turnstile/reCAPTCHA, rate limit
İnsan eliyle spam Gerçek kişiler formu elle doldurur, genellikle bağlantı içerir İçerik filtreleri, moderasyon
Bildirim istismarı Başkasının e-posta adresiyle form doldurup otomatik yanıt gönderttirir Otomatik yanıtı sınırlamak, rate limit
Başlık enjeksiyonu Alanlara satır sonu ekleyerek e-posta başlığı değiştirmeye çalışır Sunucu tarafı doğrulama

Bildirim istismarına ayrıca dikkat edin. Form ziyaretçinin yazdığı adrese “Talebinizi aldık” e-postası gönderiyorsa, saldırgan formu başkalarının adresine toplu e-posta atmak için kullanabilir. Hedef site değil, üçüncü kişilerdir. Şikâyetler ise sizin alan adınıza yazılır.

Gerçek kullanıcıyı korumak da işin parçası. Her katman, yanlış pozitif ürettiğinde bir müşteri talebini kaybettirir. Bu yüzden sıra şudur: önce kullanıcının görmediği kontroller, görünür doğrulama ancak gerekince.

Görünmez kontroller: honeypot ve zaman eşiği

Honeypot alanı

Honeypot, gerçek kullanıcının görmediği ama formun HTML’inde duran bir alandır. Alanları otomatik dolduran botlar bunu da doldurur; sunucu alan doluysa gönderimi sessizce reddeder. Etkili bir honeypot için:

  • Alan CSS ile ekran dışına taşınır; bazı botlar type="hidden" alanları ve display:none ile gizlenen alanları atladığı için bu yöntemler tek başına daha az etkilidir.
  • Alan adı makul görünür (örneğin “website” veya “firma_web”) ama formun gerçek alanlarıyla çakışmaz.
  • Ekran okuyucu ve klavye kullanıcıları için alan aria-hidden="true" taşıyan bir kapsayıcıda ve tabindex="-1" ile tab sırası dışında tutulur; tarayıcının otomatik doldurması için autocomplete="off" eklenir. Tarayıcılar bu değeri her zaman uygulamadığından alan adı “email”, “phone” gibi tipik otomatik doldurma adlarından seçilmez; aksi halde gerçek kullanıcının tarayıcısı alanı doldurur ve talep sessizce kaybolur.
  • Reddedilen gönderime başarılı yanıtı döndürülür; bot neyin yakalandığını öğrenmemeli. Reddedilenler ayrı bir günlüğe yazılır ki yanlış pozitifler incelenebilsin.

Zaman eşiği ve imzalı token

İnsan bir formu birkaç saniyeden kısa sürede dolduramaz. Form yüklenirken üretilen zaman damgası gönderimde kontrol edilir; çok hızlı (örneğin 3 saniyeden kısa) veya çok eski gönderimler reddedilir ya da ek kontrole yönlendirilir. Damga istemcide değiştirilebileceği için sunucu tarafında gizli bir anahtarla imzalanır:

<?php
// Form üretilirken
$ts    = time();
$token = $ts . '.' . hash_hmac( 'sha256', (string) $ts, FORM_SECRET );

// Gönderimde
[ $ts, $sig ] = array_pad( explode( '.', $_POST['form_token'] ?? '', 2 ), 2, '' );
$beklenen = hash_hmac( 'sha256', $ts, FORM_SECRET );
$gecen    = time() - (int) $ts;

if ( ! hash_equals( $beklenen, $sig ) || $gecen < 3 || $gecen > 7200 ) {
    // Sessizce reddet ve günlüğe yaz
}

hash_equals() zamanlama saldırılarına karşı sabit sürede karşılaştırma yapar. Sahada en sık gördüğümüz tuzak önbellektir: sayfa tam sayfa önbelleğinde (WP Rocket, Cloudflare APO veya sunucu önbelleği) tutuluyorsa token önbelleğe alındığı anın damgasını taşır ve tüm ziyaretçilere aynı değer gider. WordPress nonce’ları için de aynı sorun geçerli; nonce’lar zamana bağlı olduğundan (varsayılan ömür 24 saat) önbellekte uzun kalan bir sayfadaki nonce bir süre sonra geçersizleşir. Belirti tanıdıktır: form bir gün çalışır, ertesi gün herkese hata verir. Çözüm, token’ı sayfa yüklendikten sonra küçük bir REST veya AJAX isteğiyle almak ya da form içeren sayfaları önbellekten hariç tutmaktır. Katmanların etkileşimi için Cloudflare, WP Rocket ve Redis rehberine bakın.

CAPTCHA seçenekleri karşılaştırması

Görünmez kontroller basit botların büyük kısmını eler; sayfayı gerçek tarayıcıda açan botlar için bir doğrulama servisi gerekir. Kurumsal web sitelerindeki formlarda sık kullanılan seçenekler:

Seçenek Kullanıcı deneyimi Sunucu doğrulaması Dikkat noktası
Cloudflare Turnstile Çoğunlukla etkileşimsiz siteverify API, tek kullanımlık token Cloudflare’e veri aktarımı
reCAPTCHA v2 Onay kutusu, gerektiğinde görsel bulmaca siteverify API Bulmacalar erişilebilirliği zorlaştırabilir
reCAPTCHA v3 Etkileşimsiz, 0,0–1,0 arası skor Skor eşiğini site belirler Eşik ayarı ve düşük skorda ne yapılacağı
hCaptcha Onay kutusu veya bulmaca siteverify API Bulmaca sıklığı

Hangi servis seçilirse seçilsin kural aynı: token sunucu tarafında doğrulanmalıdır. Widget’ın yalnız istemcide yüklenmesi koruma sağlamaz; bot form uç noktasına widget olmadan doğrudan istek gönderir. “CAPTCHA var ama spam geliyor” şikâyetinin en sık nedeni budur. Turnstile için doğrulama, https://challenges.cloudflare.com/turnstile/v0/siteverify adresine gizli anahtar ve token’ın POST edilmesiyle yapılır; Cloudflare dokümantasyonuna göre token tek kullanımlıktır ve kısa bir süre (300 saniye) geçerlidir. reCAPTCHA için uç nokta https://www.google.com/recaptcha/api/siteverify adresidir. Ayrıntılar Cloudflare Turnstile dokümantasyonunda.

reCAPTCHA v3’te skor eşiği tek başına ret kararı olmamalı. Düşük skorlu gönderimi silmek yerine “şüpheli” işaretleyip ayrı kuyruğa almak, yanlış pozitiflerin satış ekibinden kaybolmasını önler.

Bu servisler ziyaretçinin IP adresi ve tarayıcı sinyalleri gibi verileri üçüncü tarafa iletir. KVKK kapsamında aydınlatma metni ve yurt dışına aktarım değerlendirmesi için servis seçimi hukuk ekibiyle birlikte yapılmalı; veri işleme tarafı KVKK uyumlu iletişim formu yazısında ele alınıyor.

Sunucu tarafı rate limit ve içerik filtreleri

Rate limit

Aynı IP’den kısa sürede çok sayıda gönderim ya bottur ya da bildirim istismarı. Sınırlama web sunucusunda, CDN/WAF katmanında veya uygulamada yapılabilir. Nginx’te limit_req modülüyle form uç noktası için ayrı bir bölge tanımlanır. Örnek Contact Form 7’nin REST uç noktası içindir; Elementor Pro formları admin-ajax.php üzerinden gönderildiği için orada farklı bir eşleşme gerekir:

# http bloğu: IP başına dakikada 5 istek
limit_req_zone $binary_remote_addr zone=formlar:10m rate=5r/m;

# server bloğu
location ~ ^/wp-json/contact-form-7/v1/contact-forms/\d+/feedback$ {
    limit_req zone=formlar burst=3 nodelay;
    limit_req_status 429;
    try_files $uri /index.php?$args;
}

Bu blok istekleri index.php’ye yönlendirir; PHP işleme, sunucudaki mevcut location ~ \.php$ bloğunda devam eder. Önde Cloudflare veya başka bir proxy varsa $binary_remote_addr ziyaretçinin değil proxy’nin IP’sini gösterebilir. Önce real_ip modülünü doğru yapılandırın; yoksa tüm ziyaretçiler tek IP gibi sınırlanır ve gerçek kullanıcılar 503 alır. Elementor Pro formlarında form eyleminin adı URL’de değil POST gövdesinde taşındığından, Nginx location eşleşmesi form gönderimini diğer admin-ajax.php çağrılarından ayıramaz; tüm admin-ajax.php trafiğine düşük sınır koymak sitenin başka işlevlerini bozar. Bu durumda sınırlama uygulama katmanında (form eklentisinin kancası) veya istek gövdesini inceleyebilen bir WAF kuralıyla yapılır. Parametreler nginx limit_req dokümantasyonunda açıklanıyor.

İçerik filtreleri

İnsan eliyle gönderilen spam teknik kontrollerin hepsini geçer. Burada içerik kuralları çalışır:

  • Mesajdaki bağlantı sayısına üst sınır; teklif formunda birden fazla URL nadiren meşrudur.
  • Alan türüne uygun doğrulama: telefon alanında yalnız rakam ve izin verilen karakterler, ad alanında URL olmaması.
  • E-posta alanında satır sonu (\r, \n) karakterlerinin reddi; başlık enjeksiyonunun temel önlemi budur.
  • Akismet gibi bir içerik sınıflandırma servisiyle şüpheli kayıtların işaretlenmesi.
  • Kurala takılan gönderimlerin silinmek yerine moderasyon kuyruğuna alınması.

İstemci ve sunucu tarafı alan doğrulamasının genel kuralları istemci ve sunucu tarafında form doğrulama rehberinde ayrıntılı anlatılıyor.

Form bildirimlerinin güvenilir teslimi

Spam’i durdurmak işin yarısı. Gerçek talep kaybolmamalı. Sık görülen teslim sorunları ve önlemleri:

  • From adresi: Bildirim ziyaretçinin adresinden değil, sitenin alan adındaki bir adresten gönderilir. Ziyaretçi adresi Reply-To başlığına yazılır. Aksi halde alıcı sunucu SPF ve DMARC kontrolünde e-postayı reddedebilir.
  • Kimlik doğrulamalı gönderim: PHP mail() yerine kimlik doğrulamalı SMTP veya bir e-posta servisinin API’si kullanılır; gönderen alan adı için SPF, DKIM ve DMARC kayıtları tanımlı olmalı.
  • Kaydı e-postadan bağımsız tutmak: Her gönderim veritabanına, CRM’e veya bir talep sistemine de yazılır. E-posta teslim edilemese bile talep kaybolmaz.
  • Otomatik yanıtı sınırlamak: Ziyaretçiye giden onay e-postası ya kaldırılır ya da yalnız tüm kontrolleri geçen gönderimlere, sınırlı sayıda gönderilir.
  • Teslim izleme: Bildirim e-postalarının hata günlükleri ve DMARC raporları düzenli incelenir.

Alan adının DMARC politikasını sıkılaştırmadan önce form bildirimleri dahil tüm meşru gönderim kaynaklarının envanteri çıkarılmalı. Envanter eksikse p=reject ilk kurbanı form bildirimi olur. Süreç DMARC’ta p=reject’e geçiş rehberinde anlatılıyor.

Spam önleme kontrol listesi

  • Honeypot alanı ekran dışında, erişilebilirlik öznitelikleriyle tanımlı; reddedilenler günlüğe yazılıyor.
  • İmzalı zaman token’ı kullanılıyor ve sayfa önbelleğiyle çakışmıyor.
  • CAPTCHA token’ı sunucu tarafında doğrulanıyor; servis seçimi KVKK açısından değerlendirildi.
  • Form uç noktası için IP bazlı rate limit var; proxy arkasında gerçek IP doğru alınıyor.
  • Bağlantı sayısı, alan türü ve satır sonu kontrolleri sunucu tarafında uygulanıyor.
  • Şüpheli kayıtlar silinmiyor, moderasyon kuyruğuna alınıyor.
  • Bildirimler alan adı adresinden, kimlik doğrulamalı gidiyor; ziyaretçi adresi Reply-To’da.
  • Her gönderim e-postadan bağımsız olarak kaydediliyor.
  • Ziyaretçiye otomatik yanıt sınırlı veya kapalı.
  • Her ay reddedilen ve kabul edilen gönderimlerden örnek alınıp yanlış pozitifler kontrol ediliyor.

Formları talep, onay ve CRM akışına bağlamak için form, talep ve onay sistemleri, veri işleme ve saklama tarafı için KVKK odaklı web formları hizmet sayfalarına bakılabilir.

Sık sorulan sorular

Honeypot alanı tek başına spam’i engeller mi?

Basit botların önemli kısmını eler; sayfayı tarayıcıda yükleyen gelişmiş botlar ve insan eliyle gönderilen spam için yetmez. Honeypot; zaman kontrolü, CAPTCHA, rate limit ve içerik filtreleriyle birlikte kullanılmalı.

Turnstile veya reCAPTCHA eklediğim halde neden spam geliyor?

En sık neden token’ın sunucu tarafında doğrulanmamasıdır. Widget yalnız istemcide yüklenirse bot form uç noktasına doğrudan istek gönderir. İnsan eliyle gönderilen spam ise CAPTCHA’yı zaten geçer; onun için içerik filtreleri ve moderasyon gerekir.

Form bildirim e-postaları neden spam klasörüne düşüyor?

Genellikle e-posta ziyaretçinin adresiyle From alanında ya da PHP mail() ile kimlik doğrulamasız gönderildiği için SPF ve DMARC kontrolleri başarısız olur. Bildirimi sitenin alan adındaki bir adresten, kimlik doğrulamalı SMTP veya API ile gönderin; ziyaretçi adresini Reply-To’ya yazın.

Sayfa önbelleği form güvenlik token’larını nasıl etkiler?

Tam sayfa önbelleğindeki bir sayfanın zaman token’ı veya WordPress nonce’u tüm ziyaretçilere aynı değerle gider ve bir süre sonra geçersizleşebilir. Token’ı sayfa yüklendikten sonra ayrı bir istekle alın ya da form içeren sayfaları önbellekten hariç tutun.

Teknik özet
Teknoloji
Cloudflare Turnstile, reCAPTCHA, Nginx limit_req, PHP, SPF/DKIM/DMARC, WordPress
Konu
Katmanlı form spam önleme
Seviye
Orta
Ön koşullar
  • Form eklentisi veya form uç noktasına erişim
  • Web sunucusu yapılandırma yetkisi
Eretek uzman desteği

Bu konu sizin ortamınızda nasıl çalışır, birlikte bakalım.

Mevcut yapınızı inceliyor, darboğazı tespit ediyor ve uygulanabilir bir iş planı öneriyoruz.