SpamAssassin'de Özel ve Meta Kurallarla Alan Adınıza Özgü Spam'i Yakalayın
sa-update ile gelen genel kural setleri yüksek hacimli spam'i yakalar; ama alan adınızı taklit eden düşük hacimli, hedefli phishing dalgaları eşiğin altından geçer. Yerel kurallar ve meta kurallarla zayıf sinyalleri birleştirip bu kör noktayı kapatmayı adım adım gösteriyoruz.
EvilMail Team24 Temmuz 202612 dk okuma
Hazır kural setlerinin göremediği şey
sa-update gece çalışır, KAM, SOUGH ve çekirdek SpamAssassin kurallarını tazeler, sonra kimse dönüp bakmaz. Bu kural setleri milyonlarca örnekten çıkarılmış imzalara dayanır ve yüksek hacimli, tanıdık spam'i gerçekten iyi yakalar. Ama kör noktaları tam da burada: bir kalıbın global bir imzaya dönüşmesi için önce dünyanın dört bir yanındaki tuzak kutulara yüzbinlerce kez düşmesi gerekir.
Size özel saldırı bu eşiğe hiç ulaşmaz. Somut senaryo: From: [email protected] gösteren, ama sizin sunucunuzdan çıkmamış, SPF softfail veren, DKIM imzası olmayan bir mesaj dalgası. Günde 5-10 tane geliyor, yalnızca sizin kullanıcılarınıza. Gövde metni markanıza göre yazılmış, URL kısaltıcı arkasına gizlenmiş. Bayes bunu "spam" diye öğrenmemiştir çünkü elinde örnek yok; ağ kuralları (RBL, DNSWL) mesaj kara listeye henüz düşmemiş, ele geçirilmiş bir VPS'ten çıktığı için susar. Toplam skor 2.0 civarında takılır, 5.0 eşiğinin çok altında, ve mesaj gelen kutusuna düşer.
İşin kaldıracı şu: alan adınızın tehdit modelini kurala dökmek. Tek başına anlamsız olan zayıf sinyalleri (acele dili + kısaltılmış URL + Reply-To uyumsuzluğu + SPF softfail) boolean ve sayım mantığıyla toplayıp, meşru postada yanlış pozitif üretmeden güvenli bir karara dönüştürürsünüz. evilmail.pro gibi geçici e-posta altyapısı işletiyorsanız kendi alan adınız sürekli taklit hedefidir; bu kör noktayı kapatmak lüks değil, operasyonel zorunluluktur.
Kural tipleri, dosya yolları ve anatomi
SpamAssassin Özel ve Meta Kurallar: Hedefli Spam'i Yakalama Rehberi — EvilMail Blog
SpamAssassin'de beş ilkel (primitive) kural tipi var, her biri mesajın farklı bir katmanını görür:
header — belirli başlıkları veya sözde başlıkları (From:addr, Reply-To:addr, To:name) inceler.
body — decode edilmiş, HTML etiketleri soyulmuş, tek satıra normalize edilmiş gövde. İnsanın okuduğu metin.
uri — gövdeden çıkarılmış URL'ler. Link temelli kalıplar için en temiz yüzey.
full — başlıklar dahil tüm ham mesaj.
Bunların üstünde meta durur: diğer kuralların boolean ve aritmetik birleşimi. Meta hiçbir metne bakmaz, sadece başka kuralların ateşleyip ateşlemediğine bakar. (Bir de eval:() fonksiyon kuralları var ama plugin gerektirir, bu yazının kapsamı dışında.)
Dosya yolları dağıtıma göre değişir. Debian/Ubuntu'da ana yapılandırma /etc/spamassassin/local.cf; RHEL/CentOS'ta /etc/mail/spamassassin/local.cf. Sistem kuralları /usr/share/spamassassin/ altındadır — buraya asla elle dokunmayın, sa-update üzerine yazar. Disiplinli yaklaşım: kendi kurallarınızı ayrı bir dosyada, örneğin /etc/spamassassin/99_local.cf içinde tutmak. Dosyalar alfabetik okunur, 99_ öneki sizinkinin en son yüklenmesini ve diğer her şeyi geçersiz kılabilmesini garantiler.
Bir kuralın anatomisi dört satırdan ibaret:
text
header SYMBOL_NAME From:addr =~ /pattern/i
describe SYMBOL_NAME İnsan tarafından okunabilir açıklama
score SYMBOL_NAME 3.5
tflags SYMBOL_NAME nice
Kritik kural: __ (çift alt çizgi) önekiyle başlayan semboller alt kuraldır (subrule). Puanlanmazlar, describe/score almazlar, tek başlarına toplam skora hiçbir katkı yapmazlar. Sadece meta kuralların içinde yapı taşı olarak kullanılırlar. Birazdan göreceğiniz birleştirme mantığının temeli budur.
İlk özel kural: kendi alan adınızı taklit eden From
Bu kural, From adresi evilmail.pro ile biten her mesajda ateşler. Sorun şu: buna tek başına puan vermek felakettir, çünkü sizin meşru dahili postanız da eşleşir. Alan adınızdan gelen olması bir mesajı kötü yapmaz; kötü yapan, alan adınızdan geliyormuş gibi görünüp kimlik doğrulamasından geçememesidir.
SpamAssassin burada devreye girer: kimlik doğrulama sonuçlarını hazır sembollere çevirir. Bunları meta içinde okuyabilirsiniz:
DKIM_VALID — geçerli herhangi bir DKIM imzası var.
DKIM_VALID_AU — geçerli imza yazar alan adına (author domain) ait. Spoofing tespitinde asıl önemli olan budur; saldırgan kendi alan adıyla geçerli DKIM imzalayabilir ama sizin alan adınız adına imzalayamaz.
Milter/amavis öncesinde SPF/DKIM doğrulayan bir katmanınız varsa (OpenDKIM veya rspamd gibi) SpamAssassin bu sonuçları Authentication-Results başlığından da okur. Böylece "alan adımdan geliyor gibi görünüyor AMA yazar-alan DKIM imzası yok VE SPF geçmiyor" ifadesini kurala dönüştürecek tüm parçalara sahip oluruz. Tek sinyal asla yeterli değildir; onları birleştirmemiz gerek.
Zayıf sinyalleri birleştirmek: meta kurallar
İki farklı meta kalıbı var ve ikisini de kullanacaksınız.
Kalıp 1 — saf boolean. Kesin bir mantıksal ifade. "Bizden geliyor gibi görünüyor VE yazar-alan DKIM'i yok VE (SPF fail VEYA softfail)."
Kalıp 2 — sayım/oylama. Hiçbiri tek başına kanıt olmayan birkaç zayıf sinyalden en az N tanesi bir arada geldiğinde ateşle. Alt kurallar boolean bağlamda 1 veya 0'a çözüldüğü için doğrudan toplanabilirler.
Tam blok, 99_local.cf içine olduğu gibi girer:
text
# --- Kendi alan adımızı taklit eden inbound ---
header __LOCAL_FROM_US From:addr =~ /\@evilmail\.pro$/i
header __LOCAL_REPLYTO_X Reply-To:addr !~ /\@evilmail\.pro$/i
body __LOCAL_URGENT /\b(acil|hemen|derhal|hesab[ıi]n[ıi]z|dogrulay[ıi]n)\b/i
uri __LOCAL_SHORTENER /https?:\/\/(bit\.ly|tinyurl\.com|t\.co|is\.gd)\//i
meta LOCAL_DOMAIN_SPOOF __LOCAL_FROM_US && !DKIM_VALID_AU && (SPF_FAIL || SPF_SOFTFAIL)
describe LOCAL_DOMAIN_SPOOF Alan adimizi taklit eden, kimlik dogrulamasi gecmeyen posta
score LOCAL_DOMAIN_SPOOF 6.0
meta LOCAL_PHISH_COMBO ( __LOCAL_URGENT + __LOCAL_SHORTENER + __LOCAL_REPLYTO_X ) >= 2
describe LOCAL_PHISH_COMBO Birden fazla phishing sinyali bir arada
score LOCAL_PHISH_COMBO 4.5
Birkaç ince nokta. __LOCAL_URGENT içindeki regex Türkçe için elle katlanmış: SpamAssassin ASCII normalizasyonu yaptığından dogrulay[ıi]n hem doğrulayın hem dogrulayin varyantını yakalar. Türkçe kural yazarken ı/i, ş/s, ğ/g çiftlerini açıkça yazmak alışkanlık olmalı, yoksa gerçek dünyadaki encoding çeşitliliği sizi ıskalatır.
meta kuralı, kullandığı tüm alt kuralların değerlendirilmesini otomatik garanti eder — priority ayarıyla uğraşmanıza gerek yok, SpamAssassin bağımlılık grafiğini kendi çözer. Bir alt kuralınız ağ gerektiriyorsa (RBL sorgusu gibi) onu tflags __ALT_KURAL net ile işaretleyin ki spamd, ağ kapalıyken sessizce yanlış sonuç üretmesin.
Puanlama, skor setleri ve yanlış pozitiften kaçınma
Varsayılan eşik required_score 5.0. Bunun altında kalan mesaj temiz sayılır. Kurallarınıza puan verirken sinyalin güvenilirliğine göre kalibre edin:
Tek, zayıf sinyal (__LOCAL_URGENT gibi bir şeyi puanlasaydınız) → 0.5–1.5. Anlamlı ama tek başına asla eşiği geçmemeli.
Yüksek güvenli meta (LOCAL_DOMAIN_SPOOF) → 4.0–6.0. Tek başına eşiği aşacak veya birkaç puanla eşiğe taşıyacak kadar.
SpamAssassin'de score aslında dört değer alabilir:
text
score LOCAL_DOMAIN_SPOOF 6.0 6.0 6.0 6.0
Dört slot sırasıyla şu kombinasyonlara karşılık gelir: (Bayes kapalı / ağ kapalı), (Bayes açık / ağ kapalı), (Bayes kapalı / ağ açık), (Bayes açık / ağ açık). Tek değer verirseniz dördüne de uygulanır — çoğu özel kural için istediğiniz budur. Dört değeri yalnızca kuralın Bayes veya ağ durumuna göre farklı davranmasını istediğinizde ayırın.
Negatif puan nice kuraldır, ham lehine oy verir. Meşru dahili postanızı korumak için bunu kullanın:
text
header LOCAL_INTERNAL_RELAY X-Originating-IP =~ /^\[212\.22\.69\.210\]/
describe LOCAL_INTERNAL_RELAY Kendi relay IP'mizden gecen dogrulanmis posta
score LOCAL_INTERNAL_RELAY -3.0
tflags LOCAL_INTERNAL_RELAY nice
Yanlış pozitif avının altın kuralı: yeni bir kuralı asla doğrudan gerçek puanıyla prod'a koymayın. Önce gözlem moduna alın — puanı 0.001 verin:
text
score LOCAL_PHISH_COMBO 0.001
Bu, kural ateşlese bile mesajın kaderini değiştirmez ama sembolü X-Spam-Report ve X-Spam-Status başlıklarına yazar. Birkaç gün log'ları ve maildir'i tarayıp kuralın kaç kez ve neyde vurduğunu görürsünüz. Meşru postada hiç ateşlemiyorsa gerçek puana (4.5) çıkarırsınız. Tek başına bu disiplin, yanlış pozitiften doğacak kullanıcı şikâyetlerinin çoğunu önler.
Test ve devreye alma döngüsü
Kural yazmak işin kolay yarısı; onu kırmadan devreye almak diğer yarısı. Sıra şöyle işler.
1. Sözdizimi doğrulama — pazarlıksız. Deploy öncesi her seferinde:
bash
spamassassin --lint
Temiz bir çıktı hiçbir şey yazmaz ve 0 döner. Bir alt kuralı meta içinde __ olmadan yazdıysanız, tanımsız bir sembole atıfta bulunduysanız ya da regex'iniz bozuksa --lint bunu "unrecognized" veya "failed to compile" diye söyler ve 0-dışı exit verir. En sinsi hata: meta içinde tanımlanmamış bir sembol kullanmak — --lint uyarır ama uyarıyı görmezden gelirseniz o meta sessizce hep 0 döner ve hiç ateşlemez.
2. Gerçek mesajla test. Maildir'den bir örnek .eml çekip debug modunda çalıştırın:
bash
spamassassin -D -t < ornek.eml 2>&1 | less
-t test modu, -D debug. Çıktıda hangi kuralların vurduğunu, meta'nın nasıl değerlendirildiğini ve nihai skoru görürsünüz. Daha temiz bir özet için sadece -t çalıştırıp üretilen X-Spam-Status başlığına bakabilirsiniz — vuran tüm sembolleri puanlarıyla listeler.
3. Performans derlemesi (isteğe bağlı). Yoğun trafikte gövde kurallarını derleyin:
4. Servisi yeniden yükleyin. Kural değişikliği kendiliğinden aktif olmaz. Standalone spamd kullanıyorsanız systemctl restart spamassassin. Ama SpamAssassin'i amavis içinden çağırıyorsanız (yaygın Postfix kurulumu) systemctl restart amavis gerekir — sadece spamassassin'i restart etmek amavis'in eski kuralları önbellekte tutmasına yol açar ve saatlerce "neden ateşlemiyor" diye kafa yorarsınız.
Bir de disiplin: değişikliği önce bir staging local.cf üzerinde --lint'ten geçirin. Bozuk bir kural dosyası, SpamAssassin'in tüm kural setini yüklemeyi reddetmesine ve filtrelemenin fail-open moda düşmesine sebep olabilir — yani her şey gelen kutusuna akar. Üretimde göze alınacak bir risk değil.
Devreye alma kontrol listesi
spamassassin --lint tertemiz mi? (uyarı bile bırakmayın)
Meta'nın kullandığı tüm__ alt kuralları tanımlı mı, hepsi çift alt çizgiyle mi başlıyor?
Puanlanan sembollerin hiçbiri yanlışlıkla __ önekli değil mi (aksi halde asla puan almaz)?
Gerçek bir ham örneği + gerçek bir spoof örneği üstünde -t ile karşı test yapıldı mı?
Skor, sinyalin güvenilirliğiyle orantılı mı? (tek sinyal ≤ 1.5, güvenli meta 4–6)
Meşru dahili posta üstünde regresyon: LOCAL_DOMAIN_SPOOF yanlışlıkla ateşlemiyor, nice kuralınız onları koruyor mu?
Yeni kural gözlem modunda (score 0.001) birkaç gün geçirdi mi, yanlış pozitif oranı sıfır mı?
Gözlemden gerçek puana geçildi, ardından doğru servis (spamassassinveyaamavis) restart edildi mi?
Restart sonrası spamd log'unda kuralın canlı trafikte vurduğu doğrulandı mı?
Global kural setleri işlerini yapmaya devam edecek, etsinler de — söküp atmak için bir sebep yok. Ama alan adınıza özel tehdit modelini yalnızca siz biliyorsunuz. LOCAL_DOMAIN_SPOOF gibi on beş satırlık bir kural, sa-update'in asla göremeyeceği, tam da sizin kullanıcılarınızı hedefleyen dalgayı eşiğin üstüne taşır. Geçici e-posta altyapısında kendi alan adınız kalıcı bir taklit hedefiyken, bu kuralları yazmak bir iyileştirme değil, filtrenizin olması gereken hali.