Mail Sunucusu Sertleştirme: fail2ban, Zorunlu TLS, Açık Relay ve SASL
Postfix + Dovecot yığınında dört gerçek saldırı yüzeyini kapatmanın sahadan çıkmış rehberi: brute-force'u fail2ban ile boğmak, TLS'i zorunlu kılmak, açık relay'i doğrulanmış biçimde kapatmak ve gönderimi SASL'a bağlamak — kopyalanabilir config satırları ve doğrulama komutlarıyla.
EvilMail Team9 Temmuz 202614 dk okuma
Açık bir mail sunucusu kurmak 20 dakika sürer: bir Postfix, bir Dovecot, bir A kaydı ve mail akıyor. Onu internete bakan bir hedef olarak güvenli tutmaksa sürekli bir iştir. 25 ve 587 portlarını açtığınız andan itibaren tarama trafiği gelir — bekleme süresi dakikalar değil, saniyelerdir. Taze bir sunucunun ilk saatindeki tipik log şudur:
Bu üç satır, kapatmanız gereken dört yüzeyin üçünü aynı anda gösteriyor: parola deneme (brute-force), kimlik olmadan gönderim denemesi (SASL) ve başkası adına relay denemesi. Dördüncüsü, TLS, log'da görünmez çünkü sorun tam da onun *görünmemesi* — şifresiz taşınan bir parola sessizce sızar. Bu yazı bu dördünü Postfix + Dovecot yığınında somut config satırlarıyla kapatır ve her adımı bir doğrulama komutuyla kanıtlar. Katmanlar birbirini tamamlar: her biri, bir öncekinin kaçırdığını yakalar.
Açık relay: önce en pahalı hatayı kapat
Açık relay'i ilk sıraya koyuyoruz çünkü diğer üç hatanın hepsi düzeltilebilir hasar verir; açık relay ise geri dönüşü en zor olanı üretir. Bir kez spam gönderen bir röle olarak Spamhaus, Barracuda ve UCEPROTECT listelerine düştüğünüzde IP itibarınızı geri kazanmak haftalar sürer ve o süre boyunca *meşru* mailiniz de geri döner. Binlerce alan adı işletirken sahada en sık gördüğümüz felaket budur ve neredeyse her zaman iki yanlıştan biridir.
Doğru relay politikası üç direktifle yazılır ve sıralama önemlidir. main.cf:
ini
# Relay hakkı SADECE localhost ve kimliği doğrulanmış istemcilere
mynetworks = 127.0.0.0/8 [::1]/128
smtpd_relay_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_unauth_destination
smtpd_recipient_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_unauth_destination,
reject_unknown_recipient_domain
Mantık şu: bir bağlantı ya mynetworks içindedir (localhost), ya SASL ile kimliğini doğrulamıştır, ya da yalnızca *sizin* alan adlarınıza teslimat yapabilir. reject_unauth_destination bunların hiçbiri değilse "kendi domain'im değil, relay yok" der ve 554 5.7.1 Relay access denied döner.
En sık gördüğümüz iki hata:
Geniş `mynetworks`. Birisi bir hosting panelinden kopyaladığı için mynetworks = 0.0.0.0/0 ya da tüm veri merkezini kapsayan bir /8 kalır. Bu, "relay hakkını dünyaya ver" demektir. mynetworks yalnızca gerçekten güvendiğiniz, kendi kontrolünüzdeki IP'leri içermelidir — çoğu kurulumda sadece localhost.
Relay kontrolünü yalnızca eski `smtpd_recipient_restrictions`'a koyup 587'yi unutmak. Postfix 2.10'dan beri smtpd_relay_restrictions ayrı bir aşamadır ve relay kararının doğru yeri odur. Kontrolü yalnızca recipient restrictions'a koyarsanız, submission portundaki override'lar bu zinciri baypas edebilir.
Değişikliği içeriden değil, dışarıdan doğrulayın. Sunucunun *dışındaki* bir makineden, üçüncü taraf bir alıcıya, sizin domain'iniz olmayan bir gönderenle relay isteyin:
Beklenen ve *istenen* yanıt 554 5.7.1 <[email protected]>: Relay access denied. Eğer 250 Ok görürseniz sunucunuz açık relaydir; başka her şeyi bırakıp bunu düzeltin.
fail2ban: brute-force'u boğmak
Relay kapalı olsa bile botlar parola denemeye devam eder. Amaç geçerli bir hesap yakalayıp *o hesapla* yasal olarak gönderim yapmaktır — o yüzden brute-force'u ayrı bir katman olarak ele almak gerekir. fail2ban, Postfix ve Dovecot log'larındaki başarısız kimlik doğrulama desenlerini sayar ve eşiği aşan IP'yi firewall seviyesinde banlar.
Modern Debian 12+ / systemd kurulumlarında en sık yapılan hata log yolunu yanlış vermektir: bu sistemlerde /var/log/mail.log çoğu zaman yoktur, loglar journald'dedir. Bu yüzden backend = systemd şarttır — fail2ban'ı olmayan bir dosyayı okumaya çalıştırırsanız jail sessizce hiçbir şey banlamaz. /etc/fail2ban/jail.local:
Neden agresif: bantime.increment = true ile aynı IP her yakalanışında ban süresini katbekat uzatır (1h → 2h → 4h...), yani ısrarcı bir bot kendi kendini haftalarca dışarıda tutar. recidive jail'i ise bir günde beş kez banlanan IP'yi bir *hafta* boyunca kapı dışarı eder — asıl sıklet buradadır, çünkü tek tek jail'lerden sürekli çıkıp giren botları toplu olarak keser. nftables-multiport backend'ini seçiyoruz çünkü modern çekirdeklerde iptables'tan daha performanslı ve IPv6'yı ek uğraşsız banlıyor; botların çoğu artık IPv6'dan da geliyor, bunu atlamayın.
Doğrulama:
bash
fail2ban-client status postfix-sasl
# Status for the jail: postfix-sasl
# |- Filter
# | |- Currently failed: 4
# | `- Total failed: 1287
# `- Actions
# `- Currently banned: 39
Currently banned sayısı taze bir sunucuda saatler içinde onlarca olur; bu normaldir ve katmanın çalıştığının kanıtıdır.
Zorunlu TLS: fırsatçıdan mecburiye
TLS'te herkesin yaptığı hata, tek bir "TLS aç" düğmesi olduğunu sanmaktır. Aslında üç ayrı yüzey vardır ve her birinde politika farklıdır.
Gelen 25 (MX). Burada TLS'i *zorunlu kılamazsınız*. İnternetteki mail sunucularının bir kısmı hâlâ TLS'siz veya bozuk sertifikayla bağlanır; port 25'te encrypt isterseniz o mailleri kaybedersiniz. Doğrusu may bırakıp güvenliği DNS katmanına (MTA-STS ve DANE) taşımaktır.
İstemci gönderimi 587/465. Burada tam tersi: TLS mecburidir ve şifresiz SASL yasaktır. smtpd_tls_auth_only = yes olmadan istemci, TLS henüz kurulmadan parolasını düz metin gönderebilir. Kurulumumuzda Dovecot parola şeması PLAIN olduğundan bu kritik: TLS zorunlu değilse PLAIN parola ağda açıkça uçar. security_level=encrypt + auth_only=yes ikilisi tam da bunu kapatır.
Giden trafik. Kendi maillerinizi gönderirken, alıcının TLSA kaydı varsa DANE ile downgrade saldırısını engelleyin.
main.cf:
ini
# Port 25: fırsatçı — mail kaybetme
smtpd_tls_security_level = may
smtpd_tls_auth_only = yes
# Modern protokol tabanı — TLSv1/1.1 kapalı
smtpd_tls_protocols = !SSLv2,!SSLv3,!TLSv1,!TLSv1.1
smtpd_tls_mandatory_protocols = !SSLv2,!SSLv3,!TLSv1,!TLSv1.1
smtpd_tls_mandatory_ciphers = high
# Giden: TLSA varsa DANE zorla
smtp_tls_security_level = dane
smtp_dns_support_level = dnssec
Dovecot tarafı (10-ssl.conf) IMAP/POP3 ve submission'ın SASL backend'i için:
Relay politikamız permit_sasl_authenticated'a dayanıyor — ama bu ancak SASL gerçekten çalışıyorsa bir şey ifade eder. Postfix'i Dovecot'un SASL soketine bağlıyoruz. main.cf:
Dovecot bu soketi Postfix'in chroot'u içinde açmalı ve Postfix kullanıcısına okuma izni vermeli (10-master.conf):
ini
service auth {
unix_listener /var/spool/postfix/private/auth {
mode = 0660
user = postfix
group = postfix
}
}
İzinler yanlışsa (0666 ya da sahibi root) submission'da her giriş SASL authentication failure: Connection refused verir — bu, "parolam yanlış mı" diye saatlerce kovaladığımız klasik tuzaktır; gerçekte sorun soket izinleridir.
Asıl kritik parça master.cf'teki submission ve submissions servis override'larıdır. Genel main.cf port 25 için gevşek TLS bırakır; submission portları bu override'larla sıkılaştırılır:
ini
submission inet n - y - - smtpd
-o syslog_name=postfix/submission
-o smtpd_tls_security_level=encrypt
-o smtpd_sasl_auth_enable=yes
-o smtpd_tls_auth_only=yes
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
-o smtpd_relay_restrictions=permit_sasl_authenticated,reject
smtps inet n - y - - smtpd
-o syslog_name=postfix/smtps
-o smtpd_tls_wrappermode=yes
-o smtpd_sasl_auth_enable=yes
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
Burada smtpd_client_restrictions=permit_sasl_authenticated,reject submission portunu sadece kimliği doğrulanmış istemcilere kilitler — anonim bir bağlantı EHLO'dan sonra hiçbir yere gidemez. Böylece 587/465 yalnızca müşteriler için, 25 yalnızca sunucular arası teslimat için ayrışır.
Aşağıdaki diyagram bir bağlantının hangi porta geldiğine göre nasıl farklı karar ağacından geçtiğini gösteriyor.
Katmanların birbirini yakalaması
Dört katmanın değeri tek tek değil, üst üste dizildiklerinde ortaya çıkar. Bir katman aşılırsa bir sonrakinin devreye girmesi gerekir. Aşağıdaki diyagram bu istifi ve her katmanın neyi durdurduğunu gösteriyor.
DNS katmanı: MTA-STS, DANE, TLS-RPT
Port 25'te TLS'i zorunlu kılamadığımız için, downgrade koruması DNS'e taşınır. Üç kayıt yayınlayın:
dns
; MTA-STS — gönderen sunuculara "bana TLS ile bağlan" der
_mta-sts.evilmail.pro. IN TXT "v=STSv1; id=2026070401"
; ve https://mta-sts.evilmail.pro/.well-known/mta-sts.txt (mode: enforce)
; TLS-RPT — TLS hatalarının günlük raporunu al
_smtp._tls.evilmail.pro. IN TXT "v=TLSRPTv1; rua=mailto:[email protected]"
; DANE/TLSA — DNSSEC imzalı bölgede downgrade'i kriptografik olarak engeller
_25._tcp.mail.evilmail.pro. IN TLSA 3 1 1 <sertifika-hash>
DANE yalnızca bölgeniz DNSSEC ile imzalıysa anlam taşır; imzasız bir TLSA kaydı hiçbir şey doğrulamaz. TLS-RPT'yi ihmal etmeyin — bir gün başka bir sunucu sizinle TLS kuramadığında bunu ancak bu raporlardan öğrenirsiniz.
Uygulama checklist'i
mynetworks'ü daraltın — localhost dışında bir şey varsa gerekçesini bilin.
smtpd_relay_restrictions'ı doğru sırayla yazın: permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination.
master.cf'te 587 ve 465 override'larını ekleyin: client_restrictions=permit_sasl_authenticated,reject.
Her değişiklik sonrası postfix check, postconf -n diff ve servis reload.
Bu config'ler bir kez yazılıp unutulan şeyler değil. fail2ban-client status çıktısını, TLS-RPT raporlarını ve reject log'larını haftalık okuyoruz; ban sayaçlarındaki bir sıçrama ya da beklenmedik bir Relay access denied deseni, bir sonraki config değişikliğini tetikleyen sinyaldir. Asıl güvenlik tek bir sertleştirme oturumunda değil, bu geri bildirim döngüsünü canlı tutmakta.