rspamd Fuzzy Hashing: Her Kopyası Farklı Gelen Kampanya Spam'ini Nasıl Yakalarsınız
Toplu spam artık iki mesajı bile birebir aynı göndermiyor; her kopyaya rastgele token, görünmez Unicode ve alıcıya özel değişkenler ekleniyor. Exact-hash imzaların ve çoğu RBL'in pas geçtiği bu polimorfik trafiği, kendi Redis destekli rspamd fuzzy storage worker'ınızı kurup honeypot'tan besleyerek dakikalar içinde nasıl bloklayacağınızı anlatıyoruz.
EvilMail Team24 Temmuz 202611 dk okuma
Aynı kampanyanın ikinci mesajı geldiğinde exact-hash imzanız onu neden tanımaz? Çünkü artık iki mesaj birebir aynı gönderilmiyor. Gövde "Merhaba {{ad}}" ile açılıyor, "Merhaba" ile "{{ad}}" arasına gözle görünmeyen bir U+200B (sıfır-genişlikli boşluk) sıkıştırılıyor, altbilgiye rastgele 6 haneli bir takip kodu ekleniyor, gövdenin en sonuna beyaz zemine beyaz yazıyla üç cümlelik salt (tuz) metin gömülüyor. Sonuç: tek bir satış metni, 500 farklı SHA-256 imzası.
Bu farkın bedeli ağır. SpamAssassin'in tam gövde imzaları ve body kuralları tek karakter değişince patlar. RBL'ler IP ve domain'e bakar; gönderen her seferinde taze bir residential proxy ya da yeni kaydedilmiş bir domain kullanıyorsa reputation henüz oturmamıştır. Kampanyanın 1. kopyası spam trap'inize düşer, siz onu manuel bloklarsınız, 2. kopya "yeni ve temiz" olarak müşterinin gelen kutusuna girer. Kaybettiğiniz şey tek bir mesaj değil; imza tabanlı savunmanın tüm mantığı.
Fuzzy hashing tam bu boşluğu kapatır. Mesajın değişen kabuğunu değil, değişmeyen iskeletini yakalar. Rastgele token da, görünmez karakter de, alıcının adı da normalize edilmiş gövdede küçük bir yer kaplar; iskelet aynı kalır. rspamd bu iskeleti shingling ve min-hash ile bir parmak izine indirger, sonra o parmak izini gelen her mesajla karşılaştırır.
Fuzzy hash, exact hash'ten nerede ayrılır
Exact hash tek bir iş yapar: tüm gövdeyi alır, tek bir SHA üretir. Girdinin tek bitini değiştirin, çıktı tümüyle değişir. Spam gönderen için bu bir zafiyet değil, hediyedir — imzanızı geçmek için tek bir görünmez karakter yeter.
rspamd Fuzzy Hashing ile Polimorfik Kampanya Spam'ini Engelleme — EvilMail Blog
Fuzzy hash aynı gövdeye çok daha temkinli yaklaşır:
Normalize et. HTML strip'lenir, metin küçük harfe çevrilir, ardışık boşluk ve noktalama sadeleştirilir, görünmez Unicode temizlenir. min_bytes eşiğinin altındaki kısa mesajlar tamamen elenir — kısa metin rastgele eşleşme ve false positive üretir.
Shingle'lara böl. Normalize metin kelime n-gram'larına (shingle) parçalanır. Her shingle bir avuç ardışık kelimedir; metin böylece örtüşen küçük parçalar dizisine dönüşür.
Min-hash ile daralt. Her shingle hash'lenir, ardından min-hash ile tüm kümeden 32 temsili değer seçilir. Bu 32'lik set mesajın parmak izidir.
Benzerliği say. İki mesajın benzerliği, 32'lik setleri arasında kaç değerin eşleştiğidir. Eşik üzeri eşleşme = aynı kampanya.
Kilit sezgi şu: rastgele bir takip kodu ya da bir U+200B karakteri metnin yalnızca birkaç shingle'ını bozar. Geri kalan onlarca shingle olduğu gibi kalır, dolayısıyla min-hash setinin çoğunluğu eşleşmeye devam eder. 32 değerden 30'u tuttuğunda rspamd "bu, daha önce gördüğüm spam'in bir varyantı" der. Aşağıdaki diyagram tam olarak bu çöküşü gösteriyor.
Mimari: fuzzy_check, storage worker ve Redis
Sistem üç parçadan oluşur:
fuzzy_check modülü — tarama sırasında, normal worker içinde çalışır. Her gelen mesajın fuzzy hash'ini hesaplar ve sorar.
fuzzy storage worker — varsayılan olarak UDP 11335'te dinler. fuzzy_check'in sorgularını alır, backend'e bakar, eşleşen değer sayısına göre bir olasılık ve skor döner.
Redis backend — hash'lerin gerçekten yaşadığı yer. Storage worker sadece protokolü konuşur; kalıcılık Redis'tedir.
Sorgu akışı düz: MTA mesajı rspamd'ye teslim eder, normal worker fuzzy_check'i çağırır, fuzzy_check şifreli bir UDP paketiyle storage worker'a sorar, o da Redis'e bakıp eşleşen değer sayısını olasılığa çevirir ve bir sembol (FUZZY_DENIED / FUZZY_PROB / FUZZY_WHITE) ile skor döndürür.
Peki neden kendi storage'ınız? Halka açık fuzzy.rspamd.com fena bir kaynak değil — rspamd varsayılan rspamd.com kuralıyla oraya bakar — ama genel bir spam feed'iyle eğitilmiştir. Size özel gönderilen dolandırıcılık dalgasını, bölgesel Türkçe spam'i, niş kampanyalarınızı görmez. Bir de gecikme ve gizlilik var: her mesajın parmak izini üçüncü tarafa sormak istemeyebilirsiniz. Kendi storage'ınız halka açık olanın yerini almaz, onu tamamlar. İkinci diyagram hem sorgu yolunu hem eğitim yolunu gösteriyor.
Kurulum: kendi Redis destekli fuzzy storage
Önce Redis'i bağlayın. /etc/rspamd/local.d/redis.conf fuzzy dahil tüm modüllerin ortak backend'i olur:
hocon
# /etc/rspamd/local.d/redis.conf
servers = "127.0.0.1:6379";
# ayrı bir DB tutmak isterseniz:
# db = "2";
Storage worker'ı tanımlayın. Şifreli sorgu için önce bir anahtar çifti üretin — çıktı UCL formatında bir pubkey/privkey ikilisi verir:
bash
rspamadm keypair -u
/etc/rspamd/local.d/worker-fuzzy.inc içine backend'i, saklama süresini, dinleme adresini ve az önce ürettiğiniz keypair'i yazın:
expire = 90d kampanya ömrüne göre seçilir. Kampanyalar dalgalar halinde döner; 90 gün, birkaç ay sonra geri gelen aynı iskeleti hâlâ yakalamanızı sağlar, Redis'i de sonsuza dek şişirmez.
Şimdi tarama tarafını /etc/rspamd/local.d/fuzzy_check.conf ile bağlayın. Buradaki encryption_key storage worker'ın public anahtarıdır — private değil:
Worker konfigürasyonunu değiştirdiğiniz için tam bir restart gerekir:
bash
systemctl restart rspamd
Sonradan yalnızca fuzzy_check.conf tarafında oynarsanız systemctl reload rspamd yeter; worker'ı yeniden başlatmanız gerekmez.
min_bytes = 1024 kritik. Kısa mesajların shingle uzayı dardır, rastgele iki kısa "teşekkürler" satırı birbirine eşleşip false positive üretir. Eşiğin altını hiç hash'lememek en temiz koruma.
Eğitim: honeypot ve spam trap'ten besleme
Bir mesajı elle spam olarak öğretmek tek komut:
bash
rspamc -w 12 -f 1 fuzzy_add spam.eml
-w 12 weight (ağırlık), -f 1 flag — flag 1 spam demektir ve FUZZY_DENIED sembolüne eşlenir. Yanlış eklediğinizde geri almak da simetrik:
bash
rspamc -f 1 fuzzy_del spam.eml
Asıl güç otomasyonda. evilmail gibi bir temp-email altyapısı işletiyorsanız elinizde sürekli akan, doğal bir spam trap var: kimse geçici adreslere meşru bülten göndermez. Bu kutulara düşen her mesajı bir cron'la flag 1 olarak besleyin — yanlış-eğitim riski düşük, çünkü o adreslerin gelen kutusu neredeyse tümüyle istenmeyen trafiktir:
bash
# honeypot maildir'ini tara, her yeni mesajı spam olarak öğret
for f in /var/mail/vhosts/trap.example/spamtrap/new/*; do
rspamc -w 12 -f 1 fuzzy_add "$f" && mv "$f" /var/mail/vhosts/trap.example/spamtrap/cur/
done
Diğer yön en az bunun kadar önemli: ham koruması. Meşru bülten ve transactional örneklerini flag 2 ile ekleyin, böylece FUZZY_WHITE sembolü tetiklenir ve o iskeletler negatif skor alır:
bash
rspamc -w 12 -f 2 fuzzy_add legit-newsletter.eml
Kaç örnek yeter sorusunun cevabı min-hash'in doğasında: tek bir varyant bile kampanyanın geri kalanını yakalar, çünkü parmak izi zaten değişmeyen iskelet üzerinden çıkar. Yine de 3-5 varyant beslemek eşleşen değer sayısını yukarı çeker ve eşik güvenini artırır. Aynı kampanyanın beş kopyasını gördükten sonra storage, altıncısını tereddütsüz DENIED yapar.
Eşik ayarı ve false positive kontrolü
max_score ile eşleşme olasılığı doğrudan ilişkilidir: eşleşen değer sayısı arttıkça olasılık 1.0'a yaklaşır ve sembol max_score'un tamamına yakınını uygular. Az eşleşmede kısmi skor gelir. Yani FUZZY_DENIED için max_score = 20.0 "tam eşleşmede 20 puan" demektir; zayıf benzerlikte bu 4-5 puana iner.
Başlarken agresif olmayın. FUZZY_DENIED skorunu reject eşiğinizin altında tutup birkaç gün rspamd history'sini izleyin. Web arayüzünde ya da history'de FUZZY_DENIED'in hangi mesajlara vurduğunu görün; meşru trafiğe hiç dokunmadığından emin olduktan sonra skoru reject eşiğine kadar yükseltin.
Birkaç ilke fuzzy'yi güvenli tutar:
Fuzzy tek karar verici olmasın. Skor katkısı olarak kullanın, mutlak blok olarak değil. Bir mesaj FUZZY_DENIED alsa bile geçerli DKIM + hizalı DMARC ile toplam skoru eşiğin altında kalabilmeli.
Bülten ve transactional'ı koruyun. FUZZY_WHITE beslemesini ihmal etmeyin; ayrıca DKIM/DMARC whitelist ile bilinen meşru göndericileri fuzzy skorunun üstüne çıkarın.
Görselli kampanyalar için image hash. Sadece resimden ibaret spam'de metin shingle'ı zayıftır; text_multiplier ve görsel fuzzy bu boşluğu kapatır.
Fuzzy'yi Bayes ile karıştırmayın — ikisi rakip değil, tamamlayıcıdır. Bayes token olasılık istatistiği tutar, kuruma göre öğrenir, "bu kelime dağılımı spam'e benziyor" der. Fuzzy ise "bu gövde daha önce gördüğüm spam'in neredeyse aynısı" der. Biri istatistiksel, diğeri imza tabanlı. İki katmanı üst üste çalıştırın.
Doğrulama ve izleme checklist
Kurulumun gerçekten çalıştığını birkaç komutla teyit edin: rspamadm fuzzy_stat storage'daki anahtar sayısını ve hit istatistiklerini verir; bir test mesajını rspamc < test.eml ile tarayıp X-Spamd-Result header'ında FUZZY_DENIED sembolünü ve skorunu görün; redis-cli DBSIZE ile hash'lerin gerçekten Redis'te yaşadığını doğrulayın.