Backscatter'ı Durdurun: Var Olmayan Alıcıyı RCPT TO'da Reddedin, Sahte Bounce Üretmeyin
Sabah kutunuzda göndermediğiniz binlerce "Mail delivery failed" mesajı varsa suçlu dışarıda değil: "kabul et, sonra reddet" mantığıyla çalışan MX'ler kendi elleriyle sahte bounce üretir. Doğru çözüm gönderme yolunda değil, alma yolundadır — alıcıyı DATA'dan önce, RCPT TO aşamasında 550 ile reddetmek. Postfix map'lerinden reject_unverified_recipient'a, SPF -all + DMARC p=reject'ten BATV'ye kadar backscatter'ı sıfıra indiren tam kurulum.
EvilMail Team26 Temmuz 202611 dk okuma
Sabah kutunuzu açıyorsunuz ve içeride hiç göndermediğiniz 4.000 tane "Mail delivery failed: returning message to sender" mesajı duruyor. Her biri gerçek bir bounce gibi görünüyor — orijinal başlıklar, MAILER-DAEMON imzası, "user unknown" gerekçesi. Ama siz o mesajların hiçbirini yollamadınız.
Mekanik şöyle işliyor: bir spam gönderici zarf-gönderenini (MAIL FROM) sizin adresinizle sahteliyor ve var olmayan bir alıcıya spam atıyor. Uzaktaki sunucu mesajı önce kabul ediyor, sonra "böyle bir kullanıcı yok" deyip bir bounce (DSN) üretiyor. Ve o bounce'u, zarftaki sahte göndericiye — yani size — geri fırlatıyor. Siz kurbansınız; ama o sahte bounce'ı üreten sunucu, aynı hatayı yapan her MX gibi, aslında saldırganın silahı. Sizin MX'iniz de aynı hatayı yapıyorsa, silah sizsiniz.
İki teslim modeli var ve aralarındaki fark hayat memat meselesi:
(a) Geç reddetme:RCPT TO
'da
250 OK
dersiniz, mesajı DATA aşamasında alırsınız, sonra alıcının olmadığını fark edip
lokal bir bounce üretirsiniz
. O bounce artık sizin sorumluluğunuzda, zarftaki (muhtemelen sahte) göndericiye gider. Backscatter'ın kaynağı tam olarak budur.
(b) Erken reddetme:RCPT TO'da 550 5.1.1 User unknown dersiniz. Mesaj hiç kabul edilmez, DATA hiç akmaz, hiçbir DSN üretmezsiniz. Bounce'u üretmek zorunda kalan taraf, mesajı size ulaştıran üst sunucudur — ve sorumluluk asıl göndericide kalır.
(a) yolunun bedeli sadece kutunuzdaki çöp değil. IP'niz backscatterer.org (UCEPROTECT Level 0) gibi tuzak (trap) listelerine düşer. Bu listeler, dışarıya bounce ve callout gönderen IP'leri toplar. Listeye düştüğünüz an, bu RBL'i kullanan sunuculara giden giden postanız reddedilmeye başlar. Yani birinin sizi taklit etmesiyle başlayan olay, kendi teslim edilebilirliğinizin çökmesiyle biter.
Tek kural: alıcıyı RCPT TO'da doğrula, DATA'dan önce reddet
Backscatter'ı önleyen ilke tek cümleye sığar: geçerli alıcı kümesini, mesajın gövdesini görmeden bilmek zorundasınız. Alıcının var olup olmadığını ancak mesajı depoladıktan sonra öğrenen bir sunucu, bounce üretmeye mahkûmdur. Bu bilgiyi RCPT TO anında, yani DATA'dan önce elinizde bulundurursanız, cevabınız tek bir 550 olur ve iş biter.
Postfix bu geçerli alıcı listesini dört yerden bilebilir: local_recipient_maps, virtual_mailbox_maps, virtual_alias_maps ve relay_recipient_maps. smtpd_reject_unlisted_recipient = yes (Postfix 2.1'den beri varsayılan) bu map'lerin hiçbirinde olmayan alıcıyı otomatik olarak RCPT aşamasında reddeder. reject_unlisted_recipient ise aynı davranışı restriction listenizde açıkça zorunlu kılar.
Kaçınmanız gereken anti-pattern'ler, tam olarak backscatter üreten kalıplardır:
Boş `local_recipient_maps` — Postfix o zaman her yerel adrese 250 verir. Alıcı yoksa mesaj sonradan bounce olur.
`luser_relay` tanımlamak — tanımsız alıcıları bir "yakalayıcı" kutuya yönlendirir; pratikte her adresi geçerli sayar.
`virtual_alias_maps` içinde wildcard catch-all (@domain → biri) — bilinmeyen her alıcıyı kabul eder.
İçerik filtresinde "karantinaya al + göndericiye bildir" — spam kararını kabul ettikten sonra veren, sonra da göndericiye DSN yollayan her yapı.
Postfix: sanal alıcı haritaları ve reject_unlisted_recipient
evilmail'in kurulumu MySQL tabanlı sanal alıcılar üzerine oturuyor (mailserver DB, virtual_users tablosu). main.cf'te ilgili blok:
Sıralama önemli. reject_unauth_destination en başlarda çünkü açık relay'i kapatır — bize ait olmayan domainlere teslim istenirse 554 Relay access denied döner. Ama backscatter'ın asıl işi reject_unlisted_recipient'ta: domain bize aitse ama alıcı map'te yoksa 550 User unknown döner. Sorgu dosyası (mysql-virtual-mailboxes.cf) şuna benzer:
ini
user = mailuser
password = your_strong_db_password
hosts = 127.0.0.1
dbname = mailserver
query = SELECT 1 FROM virtual_users WHERE email='%s'
Bu tek satırlık SELECT, mesajın gövdesi hiç görünmeden RCPT aşamasında çalışır. Alıcı kutusu Dovecot'a LMTP ile teslim edildiğinde artık "user unknown" ihtimali sıfırdır — çünkü geçersiz alıcı zaten kapıdan içeri hiç girmemiştir.
Gateway/relay önünde: reject_unverified_recipient
Ön MX'iniz asıl mailbox'ları barındırmıyorsa — yani arka uçtaki (backend) alıcı listesini bilmiyorsa — iki seçeneğiniz var.
Temiz yol: arka uç alıcı listesini statik olarak senkronize edip relay_recipient_maps ile okumak.
Burada bir uyarı: probe yaparken kendiniz backscatter/callout-abuse üretmeyin. Rastgele adresleri sürekli doğrulamaya çalışırsanız backscatterer.org sizi callout kaynağı olarak listeler. Bu yüzden önbelleği kalıcı tutun, unverified_recipient_reject_code'u 450 yerine 550 yapın (geçici değil kalıcı ret) ve negatif önbellek yenileme süresini makul verin. Elinizden geliyorsa relay_recipient_maps yolunu tercih edin — callout hiç yapmazsınız.
İçerik filtresini de SMTP anında reddet, sonra bounce'lama
Aynı ilke spam ve virüs kararı için de geçerli: kararı oturum içinde `5xx` ile verin, mesajı alıp sonra göndericiye "spam'di, geri dönüyor" diye DSN yollamayın. "Karantina + bildir" kalıbı backscatter'ın ikinci büyük kaynağıdır, çünkü zarf-gönderen genellikle sahtedir.
amavis:$final_spam_destiny = D_REJECT; — D_BOUNCEdeğil. D_BOUNCE tam olarak backscatter üretir.
Genel milter kuralı: karar verilemeyen durumda tempfail (4xx) uygun; ama "spam" kararı verildiyse mesajı kabul edip sonra bounce'lamak yerine reject dönün.
Gelen sahte bounce'ları kesmek: SPF -all, DMARC p=reject, BATV
İki cephede savaşırsınız. Birincisi: başkalarının sizi taklit etmesini pahalı hale getirmek. SPF -all ve DMARC p=reject yayınlarsanız, bounce üretmeden önce SPF kontrolü yapan sunucular sahteciliği görüp mesajı reddeder — DSN hiç doğmaz.
dns
evilmail.pro. IN TXT "v=spf1 ip4:203.0.113.10 -all"
_dmarc.evilmail.pro. IN TXT "v=DMARC1; p=reject; rua=mailto:[email protected]; adkim=s; aspf=s"
İkincisi: her şeye rağmen kapıya gelen backscatter'ı tanımak. Gerçek bir DSN'in zarf-göndericisi her zaman boştur (MAIL FROM:<>). Buradan hareketle BATV/PRVS kullanırsınız: giden postanızda zarf-göndericiyi [email protected] biçiminde imzalarsınız. Gelen bir boş-zarf DSN'de bu imza yoksa veya süresi geçmişse, o bounce sizden çıkmamış bir mesaja aittir — reddedersiniz. Postfix'te native BATV yoktur; batv-milter / signing-milter ile eklersiniz. Yönlendirme (forward) yapıyorsanız postsrsd ile SRS'i de devreye alın ki imzalar forward zincirinde bozulmasın.
Doğrulama ve izleme
Kurulumu bittiğinde swaks ile var olmayan bir alıcıya test atın ve RCPT aşamasında ret bekleyin:
Bu satırı görüyorsanız, mesaj DATA'ya hiç ulaşmadı ve hiçbir DSN doğmadı. Sonra loglarda accept-then-bounce izini avlayın ve kuyrukta dışarı giden bounce yığını olup olmadığına bakın:
bash
grep -E "status=bounced" /var/log/mail.log | grep MAILER-DAEMON
postqueue -p | grep -c "MAILER-DAEMON" # dışarı giden bounce sayısı
postconf smtpd_reject_unlisted_recipient # = yes olmalı
Metrik hedefiniz nettir: sağlıklı bir MX'in dışarıya ürettiği lokal DSN sayısı pratikte ~0'dır.postqueue -p çıktısında MAILER-DAEMON yığılması görüyorsanız, bir yerde hâlâ kabul edip sonra reddediyorsunuz. Son olarak IP'nizi backscatterer.org'da sorgulayın; temizse doğru yoldasınız.
evilmail notu: catch-all ama disiplinli
Temp-mail servisi doğası gereği catch-all'dır — kullanıcı [email protected] yazar ve mesaj gelmelidir. Ama catch-all olmak, backscatter üretmek için mazeret değildir:
Catch-all yalnızca hizmet verdiğimiz domainlerle sınırlıdır (evilmail.pro, evilmail.cloud). Bilinmeyen bir domaine teslim istenirse RCPT'te reddedilir.
Bilinen domaindeki alıcı kabul edilir ama hiçbir koşulda DSN üretilmez. Depolama dolu, kutu süresi dolmuş, ne olursa olsun: bounce yerine sessizce depola/at.
Rate-limit uygulanır ki catch-all bir spam çöplüğüne dönüşmesin.
Yani ilke tersine dönmüş gibi görünse de aynıdır: kabul kararını kapıda ver, sonradan reddedip bounce üretme.
Kontrol listesi
Var olmayan alıcıya swaks testi RCPT aşamasında 550 5.1.1 dönüyor mu?