Sorun: "kontrol ediyoruz" ile "cezalandırıyoruz" arasındaki uçurum
Bir mail sunucusu kurup rspamd'ı devreye alıyorsun, spf, dkim, dmarc modülleri açık, rspamc çıktısında DMARC_POLICY_REJECT sembolü güzelce görünüyor. Sonra birisi [email protected] adına sahte bir mail atıyor ve o mail kullanıcının gelen kutusuna — iyi ihtimalle spam klasörüne — düşüyor. Nasıl?
Çünkü sembolün *görünmesi* ile mesajın *reddedilmesi* aynı şey değil. Varsayılan kurulumda DMARC_POLICY_REJECT çoğunlukla 1-2 puan taşır. Reject eşiğin 15. Aradaki 13 puanlık boşluğu spam filtresinin geri kalanının doldurması gerekir — ama iyi yazılmış bir phishing mailinde doldurulacak bir şey yoktur: temiz HTML, kötü kelime yok, URL reputation temiz. Sonuç: DMARC politikası p=reject diyen bir domainden gelen açıkça sahte mesaj, senin sunucunda "biraz şüpheli" muamelesi görüp teslim edilir.
Bu yazının tezi tek cümle: kimlik doğrulama sonucu bir bilgi değil, bir skor manivelasıdır. DMARC "fail" sonucunu loglamak yetmez; onu reject eşiğine yaslayacak ağırlığa ve — kritik senaryolarda — skor aritmetiğinden bağımsız deterministik bir aksiyona bağlamak gerekir. İki cepheyi ayrı ayrı savunacağız: yabancı domain spoofing'ini header authentication ile, kendi domainlerimizi impersonation kuralıyla. Ve bunu yaparken meşru forwarder ve mailing-list trafiğini yakmayacağız.
Zincir nasıl akıyor: SPF → DKIM → DMARC → ARC
Ağırlık ayarlamadan önce her katmanın *neyi kanıtladığını* netleştirmek şart, çünkü yanlış katmana yaslanmak en yaygın false-positive kaynağıdır.
- SPF zarf gönderenini (RFC5321
MAIL FROM, envelope-from) doğrular: "bu IP bu domain adına mail atmaya yetkili mi?" Kullanıcı bu adresi görmez. Forwarding bu zarfı değiştirdiği için SPF forwarding'e karşı kırılgandır. - DKIM mesajın belirli başlıklarını ve gövdesini kriptografik olarak imzalar. İmza, header'lar bozulmadığı sürece forwarding'e dayanır. Bu yüzden DKIM güvenilir dayanaktır.
- DMARC asıl olayı yapar: alignment. Kullanıcının gördüğü
From:(RFC5322 header-from) ile SPF veya DKIM'in doğruladığı domain hizalı mı?relaxedhizalamada organizasyonel domain yeter,strict'te birebir eşleşme gerekir. DMARC "pass" demek için ya aligned SPF ya aligned DKIM ister. - ARC forwarding zincirinde önceki sunucunun doğruladığı sonucu kriptografik olarak taşır. Google veya bir mailing-list araya girip mesajı değiştirdiğinde DMARC kırılır ama ARC "ben teslim aldığımda bu mail temizdi" der.
rspamd bu katmanları sırasıyla spf, dkim, dmarc, arc modülleriyle işler; her birinden bir sembol üretip skora ekler ve Authentication-Results başlığını yazar:
Authentication-Results: mx.evilmail.pro;
dkim=fail reason="no signature";
spf=pass smtp.mailfrom=bounce.attacker.net;
dmarc=fail (p=reject) header.from=paypal.comBu başlıktaki üçlüye dikkat: SPF pass (çünkü saldırganın kendi zarf domaini geçerli), ama header-from paypal.com ve DMARC fail. Alignment olayı tam burada. SPF'in tek başına "pass" demesi hiçbir şey ifade etmiyor — DMARC failini ciddiye almazsan bu mail geçer.
Sembol ağırlıklarını gerçekten anlamlı kıl
Modül davranışını local.d/dmarc.conf, local.d/dkim.conf, local.d/spf.conf ile ayarlarsın, ama asıl kaldıraç sembol *ağırlıkları*dır ve onlar local.d/groups.conf içinde override edilir. Amaç: p=reject politikası olan bir domainden gelen bir fail'in tek başına reject eşiğine yaklaşması.
/etc/rspamd/local.d/groups.conf:
symbols {
"DMARC_POLICY_REJECT" { weight = 7.0; }
"DMARC_POLICY_QUARANTINE" { weight = 4.0; }
"R_DKIM_REJECT" { weight = 4.0; }
"R_SPF_FAIL" { weight = 3.0; }
"R_SPF_SOFTFAIL" { weight = 1.0; }
"FORGED_SENDER" { weight = 3.0; }
}Neden bu sayılar? DMARC_POLICY_REJECT = 7 demek, aynı mailin arkasına yığılacak birkaç zayıf sinyalle (mesela R_DKIM_NA ve FROM_NEQ_ENVFROM) toplamın rahatça 10-12'yi bulması, junk eşiğini kesin geçmesi ve reject eşiğine dayanması demektir. R_SPF_FAIL'ı bilinçli olarak 3'te tutuyorum — daha fazlası forwarding'i yakar (birazdan). DKIM reject'e daha çok güveniyoruz çünkü imza doğrulanmışsa ve reject dönüyorsa mesaj gerçekten kurcalanmıştır.
Değişikliği yükleyip efektif ağırlığı doğrula:
systemctl reload rspamd
rspamadm configdump | grep -A2 DMARC_POLICY_REJECT
# symbol { name = "DMARC_POLICY_REJECT"; weight = 7; ... }
rspamadm configtest
# syntax OKconfigdump sana rspamd'ın gerçekten *kullandığı* değeri gösterir; .conf dosyanda 7 yazıp da configdump'ta 2 görüyorsan bir yerde başka bir override seni eziyor demektir (override.d/ local.d/'yi tümden ezer — sırayı karıştırma).
force_actions: eşik aritmetiğine güvenmeyi bırak
Ağırlık ayarı iyileştirir ama garanti etmez. Skor toplamı kaygandır: pozitif ağırlıklar kadar negatif ağırlıklar da (whitelist, bayes ham, reputation) toplama girer ve iyi hazırlanmış bir phishing bunları toplamaya çalışır. Kritik senaryoda skora değil, koşula güvenmek istersin.
/etc/rspamd/local.d/force_actions.conf:
rules {
reject_dmarc_reject {
action = "reject";
expression = "DMARC_POLICY_REJECT & !ARC_ALLOW & !WHITELIST_DMARC";
message = "Rejected: sender domain DMARC policy is p=reject";
}
reject_own_domain_unsigned {
action = "reject";
expression = "OWN_DOMAINS & !DMARC_POLICY_ALLOW & !ARC_ALLOW";
message = "Rejected: unauthenticated mail claiming our domain";
}
}Birinci kural şunu der: DMARC politikası reject olan bir domainden fail geldiyse ve güvenilir bir ARC zinciri yoksa ve bilinçli bir DMARC whitelist'i yoksa — skor ne olursa olsun reddet. ARC_ALLOW istisnası kritik; onsuz bütün mailing-list trafiğini kaybedersin. İkinci kuralı bir sonraki bölümde kuracağız.
Kendi domainlerini koru: impersonation katmanı
Asıl tehlike genelde yabancı bir domain değil, senin domainin adına gelen sahte mail — çünkü kullanıcı @evilmail.pro'dan gelen bir maile refleksle güvenir. Bunu jenerik DMARC mantığıyla değil, açık bir "bu bizim domainimiz" kuralıyla vurmalısın.
Önce bir map dosyası, /etc/rspamd/local.d/maps.d/own_domains.map:
evilmail.pro
evilmail.cloudSonra bu map'i header-from üzerinde eşleştirip bir sembol üret, /etc/rspamd/local.d/multimap.conf:
OWN_DOMAINS {
type = "header";
header = "from";
filter = "email:domain";
map = "${LOCAL_CONFDIR}/local.d/maps.d/own_domains.map";
symbol = "OWN_DOMAINS";
score = 0.0;
}Skoru bilinçli olarak 0.0 bırakıyoruz — bu sembol tek başına ceza vermez, sadece "header-from bizim domainlerimizden biri" bilgisini işaretler. Cezayı yukarıdaki force_actions.conf'taki reject_own_domain_unsigned kuralı verir: OWN_DOMAINS & !DMARC_POLICY_ALLOW & !ARC_ALLOW. DMARC_POLICY_ALLOW sadece hizalı (aligned) bir SPF ya da DKIM pass'te doğar; bilinçli olarak !R_DKIM_ALLOW yazmadık, çünkü o sembol *herhangi* geçerli bir imzada — saldırganın kendi domaini için attığı imza dahil — doğar ve alignment'ı denetlemez. Yani birisi From: EvilMail <[email protected]> yazıp da bizim domainimizle hizalı geçerli bir imza sunamıyorsa — mesajın nereden geldiğinin önemi yok — reddedilir. Kendi giden mailin zaten hizalı DKIM imzalı olduğu için bu kural meşru trafiğini asla vurmaz.
DNS tarafında bu korumayı en sert hale getirmek için kendi domaininin _dmarc kaydını strict alignment'a çek:
_dmarc.evilmail.pro. IN TXT "v=DMARC1; p=reject; adkim=s; aspf=s; rua=mailto:[email protected]"adkim=s; aspf=s ile bir saldırgan mail.evilmail.pro.attacker.com gibi alt domain oyunlarıyla relaxed hizalamayı kandıramaz.
Meşru trafiği yakma: forwarder, mailing list, ARC, SRS
Sertleştirmenin bedeli false-positive'dir ve en büyük tuzak SPF'e fazla yaslanmaktır. Bir kullanıcı mailini Gmail'e forward ettiğinde forwarding sunucusu zarf gönderenini korur ama IP değişir → SPF fail. Eğer R_SPF_FAIL'a 6-7 puan verirsen bütün forward edilmiş meşru maili spam'e atarsın. Bu yüzden R_SPF_FAIL'ı 3'te bıraktık ve reject kararını asla tek başına SPF'e dayamadık.
Doğru dayanak DKIM'dir, çünkü imza forwarding'e dayanır. İki mekanizma false-positive'i kapatır:
- ARC: Bir mailing-list mesaja
[liste]öneki ekleyip footer bastığında DKIM ve DMARC kırılır. Ama liste sunucusu mesajı teslim aldığında temizdiyse bunu ARC imzasıyla taşır.force_actionskurallarındaki!ARC_ALLOWistisnası tam da bu senaryoyu kurtarır — güvendiğin bir forwarder zinciri varsa reject'i iptal edersin. - SRS (Sender Rewriting Scheme): Kendi sunucun başkası adına mail forward ediyorsa, zarf gönderenini yeniden yaz ki *senin* çıkışın alıcının SPF kontrolünden geçsin. Postfix tarafında
postsrsdile hallolur; bu, forward ettiğin mailin karşı tarafta SPF'ten patlamamasını sağlar.
Büyük sağlayıcılar için DKIM tabanlı bir whitelist ile skoru *düşürebilirsin* (whitelist.conf), ama bir kuralı asla çiğneme: kendi domainini hiçbir zaman whitelist'e koyma. Aksi halde impersonation katmanını kendi elinle deldin demektir.
Doğrula: swaks ve rspamc ile deney
Teoriyi bırak, sahte mail at ve reddedildiğini gör. Kendi domainini impersonate eden bir mesajı swaks ile enjekte et:
swaks --to [email protected] \
--from "[email protected]" \
--header "From: EvilMail Support <[email protected]>" \
--server 127.0.0.1Beklenen sonuç: SMTP oturumunda 550 Rejected: unauthenticated mail claiming our domain. Bir .eml dosyasını doğrudan tarayıp sembol dökümünü de görebilirsin:
rspamc < spoofed.eml
# Action: reject
# Symbol: OWN_DOMAINS (0.00)
# Symbol: R_DKIM_NA (0.00)
# Symbol: DMARC_POLICY_REJECT (7.00)
# Symbol: FORCE_ACTION (reject)Ve logda kararın izini sür:
tail -f /var/log/rspamd/rspamd.log | grep 'reject'
# ... (default: F (reject): [16.40/15.00] ... DMARC_POLICY_REJECT(7.00)...)[16.40/15.00] yani toplam skor / reject eşiği. force_actions devredeyse skor 15'in altında olsa bile FORCE_ACTION ile reject görürsün — istediğimiz de buydu.
Devreye alma checklist'i
local.d/groups.conf'taDMARC_POLICY_REJECT,R_DKIM_REJECT,R_SPF_FAILağırlıklarını yaz,R_SPF_FAIL'ı 3'ün üstüne çıkarma.own_domains.map+multimap.confileOWN_DOMAINSsembolünü kur (score 0.0).force_actions.conf'aDMARC_POLICY_REJECT & !ARC_ALLOWveOWN_DOMAINS & !DMARC_POLICY_ALLOW & !ARC_ALLOWkurallarını ekle.arcmodülünün açık olduğunu doğrula — yoksa mailing-list ve forward trafiğini reddedersin.- Her değişiklikten sonra
rspamadm configtest
Kimlik doğrulama, sonucunu skora bağlamadığın sürece dekoratif bir başlıktan ibarettir. Ağırlıkları anlamlı kıl, kritik senaryolarda force_actions ile aritmetiği baypasla, kendi domainini ayrı bir katmanla koru — ama ARC ve SRS'i devrede tutarak meşru gönderenleri ayakta tut. O zaman DMARC_POLICY_REJECT bir logdan çok, bir kapıya dönüşür.


