Çoğu rspamd kurulumu SPF/DKIM/DMARC'ı "kontrol ediyor" ama sonucu skora bağlamıyor: DMARC fail bir mesaj +2 puanla junk klasörüne düşüp teslim ediliyor. Kimlik doğrulama sonucunu bir skor manivelasına çeviriyoruz — force_actions, sembol ağırlıkları ve impersonation katmanıyla p=reject alan bir domainden gelen spoof'u deterministik olarak reddedip meşru forwarder trafiğini ARC/SRS ile ayakta tutuyoruz.
EvilMail Team24 Temmuz 202613 dk okuma
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ı
rspamd Authentication Skorlama: SPF/DKIM/DMARC ile Spoof Reddetme — EvilMail Blog
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ı? relaxed hizalamada 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:
Bu 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ı.
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:
bash
systemctl reload rspamd
rspamadm configdump | grep -A2 DMARC_POLICY_REJECT
# symbol { name = "DMARC_POLICY_REJECT"; weight = 7; ... }
rspamadm configtest
# syntax OK
configdump 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.
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:
text
evilmail.pro
evilmail.cloud
Sonra bu map'i header-from üzerinde eşleştirip bir sembol üret, /etc/rspamd/local.d/multimap.conf:
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:
text
_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.
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_actions kurallarındaki !ARC_ALLOW istisnası 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 postsrsd ile 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:
Beklenen 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:
[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'ta DMARC_POLICY_REJECT, R_DKIM_REJECT, R_SPF_FAIL ağırlıklarını yaz, R_SPF_FAIL'ı 3'ün üstüne çıkarma.
own_domains.map + multimap.conf ile OWN_DOMAINS sembolünü kur (score 0.0).
arc modülünün açık olduğunu doğrula — yoksa mailing-list ve forward trafiğini reddedersin.
Her değişiklikten sonra rspamadm configtest, ardından systemctl reload rspamd (restart değil; reload yeter).
rspamadm configdump | grep <SYMBOL> ile efektif ağırlıkların gerçekten uygulandığını doğrula.
swaks ile hem yabancı p=reject domaini hem de kendi domainin için spoof testi yap; logda F (reject) gör.
Kendi domainlerinin _dmarc kaydını p=reject; adkim=s; aspf=s yap.
İlk 48 saat /var/log/rspamd/rspamd.log'u izle: yanlışlıkla reddedilen meşru gönderen varsa DKIM/ARC istisnasını genişlet, ağırlıkları düşürme.
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.