Postfix master.cf: 587 ve 465 Portlarını Farklı Güven Sınırlarıyla Ayırmak
Çoğu Postfix kurulumu 587 ile 465'i tek bir kopyala-yapıştır bloğuyla açar. Oysa master.cf her satırı ayrı bir smtpd örneği olarak çalıştırır; asıl güç, iki portu farklı -o override setleriyle ayrı politikalara bağlamakta. İnsan istemcisi için sıkı submission, makineler için implicit-TLS'li ayrı yol.
EvilMail Team11 Temmuz 202612 dk okuma
Elinizdeki master.cf'te 587 ve 465 için satır satır aynı -o bloğu duruyorsa, iki farklı güven sınırını tek politikayla yönetiyorsunuz demektir. Bu, kopyala-yapıştırın en pahalı türü: tek bir sızmış istemci parolası hem insan kullanıcı hem servis hesabı trafiğinin tamamını açığa çıkarır, log'larda iki sınıfı ayıramazsınız ve port bazlı hiçbir politika (HELO, sender login map, boyut, eşzamanlılık) uygulayamazsınız.
Oysa master.cf'teki her satır ayrı bir daemon örneğidir. smtpd bir program değil, bir şablondur; aynı ikili dosyayı farklı -o override setleriyle iki ayrı süreç olarak çalıştırırsınız. Bu yazının iddiası basit: 587'yi \"insan + zorunlu STARTTLS + SASL + agresif rate limit\" için, 465'i \"makineler / uygulama sunucuları / relay istemcileri için implicit-TLS'li ayrı gönderim yolu\" için yapılandırın. İki port, iki daemon, iki politika.
Önce şu yanlışı düzeltelim: 465 deprecated değil
Uzun süre dolaşan \"465 eski/ölü port, STARTTLS kullanın\" nakaratı 2018'de bitti. RFC 8314
Postfix master.cf ile 587 ve 465 Portlarını Ayırma | evilmail — EvilMail Blog
, submission için implicit TLS'i (yani 465'i) açıkça *önerilen* yol hâline getirdi. Tablo şöyle netleşiyor:
Port 25 — MTA-to-MTA relay. Kimlik doğrulaması olmamalı, opportunistic TLS, SASL kapalı. İstemci gönderimi buraya asla düşmemeli.
Port 587 — submission (RFC 6409). Bağlantı düz metin başlar, STARTTLS (RFC 3207) ile şifreli kanala yükseltilir.
Port 465 — smtps / implicit TLS. İlk byte'tan itibaren TLS; STARTTLS komutu yoktur, olması da hatadır.
587'deki STARTTLS öncesi kısa düz-metin penceresi, ortadaki bir saldırganın STARTTLS yeteneğini EHLO yanıtından silerek bağlantıyı şifresiz bırakmasına (STARTTLS stripping) zemin bırakır. 465'te bu pencere sıfırdır. İkisini de tutmanın nedeni budur: 587 geniş istemci uyumluluğu için, 465 downgrade yüzeyi olmayan yol için.
master.cf satır anatomisi: sekiz sütun ne yapıyor
Bir servis satırı sekiz sütundan oluşur:
# service type private unpriv chroot wakeup maxproc command + args
submission inet n - y - - smtpd
service — port numarası ya da /etc/services'teki isim (submission = 587, smtps = 465).
type — inet (TCP soketi) veya unix (yerel soket). Gönderim portları inet.
private — sadece Postfix mi erişebilir. inet servisleri dışa açık olduğundan zorunlu olarak n.
maxproc — bu servisin çalışabilecek eşzamanlı süreç sayısı, yani kaba bir eşzamanlılık limiti. - global default_process_limit'i (100) kullanır.
command + args — çalışacak daemon (smtpd) ve ona geçen -o key=value override'ları.
Kilit nokta -o'nun semantiği: her -o yalnızca o daemon örneğine ait main.cf değerini ezer. main.cf'i değiştirmez, komşu servisi etkilemez. Yani main.cf'te smtpd_sasl_auth_enable=no global kapalıyken, submission satırında -o smtpd_sasl_auth_enable=yes sadece 587'de SASL'ı açar. Port 25 anonim kalır. Güvenlik modeliniz tam olarak buna dayanır.
Mevcut hâli makine-okur formatta görmek için:
bash
postconf -M # tüm master.cf servisleri
postconf -Mf # formatlı, -o'lar tek tek satırlarda
postconf -P # per-servis override'ları listeler
587 submission bloğu: insan kullanıcı için sıkı gönderim
Bu port bir kişinin posta istemcisinden (Thunderbird, iOS Mail, webmail arka ucu) geldiği varsayımıyla kilitlenir:
`smtpd_tls_security_level=encrypt` — TLS zorunlu. STARTTLS yapmayan istemci MAIL FROM'a ulaşamaz. may (opportunistic) burada kabul edilemez; submission'da şifresiz gönderime izin vermezsiniz.
`smtpd_tls_auth_only=yes` — SASL yalnızca TLS kurulduktan sonra teklif edilir. Parola düz metin ağa hiç çıkmaz.
`smtpd_sasl_type=dovecot` + `smtpd_sasl_path=private/auth` — kimlik doğrulama Dovecot'un SASL soketine devredilir. chroot açıksa yol /var/spool/postfix/private/auth altında göreli çözülür.
`...restrictions=permit_sasl_authenticated,reject` — kimliği doğrulanmamış herkes reddedilir. Açık relay kapısı yok.
`smtpd_sender_login_maps` + `reject_sender_login_mismatch` — asıl güçlü kısım. Bu ikisi, giriş yapan kullanıcının yalnızca kendisine izin verilen From/envelope adresinden gönderebilmesini zorlar. [email protected] olarak oturum açan biri [email protected] adına mektup yollayamaz. Dahili spoofing'i envelope seviyesinde keser.
`smtpd_tls_wrappermode=yes` — bağlantı TCP handshake'inin hemen ardından TLS handshake ile başlar. Burada smtpd_tls_security_level=encrypt yazmazsınız; wrappermode zaten TLS'i zorunlu kılar, ikisi birlikte kullanılmaz. Bir istemci bu porta STARTTLS beklentisiyle gelirse bağlantı kurulamaz — ve bu doğru davranıştır.
Ayrı politika değerleri — message_size_limit 50 MB'a çıkarıldı (rapor eki, yedek dökümü gönderen servisler için), smtpd_client_message_rate_limit 200'e yükseltildi. 587'de bu değer 10'du. Makine trafiği yüksek hacimli ama sayısı belli hesaplardan gelir; insan trafiği tersine düşük hacimli ve çok sayıda hesaptan. İki eşiği ayırmak, birinin diğerini boğmasını engeller.
İsterseniz 465 için ayrı bir smtpd_sender_login_maps dosyası tanımlayıp servis hesaplarını insan hesaplarından tamamen ayrı bir kimlik havuzunda tutabilirsiniz. Böylece bir uygulama parolasının sızması, insan kullanıcı adres alanına dokunamaz.
İki portu farklı kısıtlamalarla ayırmanın pratiği
Somutlaştıralım. Hedef politika:
587 — insan hesapları, TLS sonrası SASL, istemci başına dakikada 10 mesaj, sender_login_maps ile From kilidi.
465 — servis hesapları, yüksek throughput (dakikada 200), 50 MB gövde, ağ katmanında IP allowlist.
Rate limiting'i anvil yürütür; anvil_rate_time_unit varsayılan 60 saniyedir. Yani smtpd_client_message_rate_limit=10 \"IP başına 60 saniyede 10 mesaj\" demektir. Bağlantı seli için smtpd_client_connection_rate_limit ekleyin. Bu değerleri port başına -o ile ayırdığınızda, tek bir istemcinin 587'yi doldurması 465'i etkilemez.
Postfix 3.x'te uzun -o listelerini okunur tutmak için çok satırlı blok sözdizimini kullanın:
smtps inet n - y - - smtpd
-o { smtpd_tls_wrappermode=yes }
-o { smtpd_sasl_auth_enable=yes }
-o { smtpd_client_message_rate_limit=200 }
IP allowlist'i uygulama katmanında check_client_access ile ya da daha temizi ağ katmanında UFW ile kurabilirsiniz. Portları açarken 25'i asla aynı politikaya sokmayın:
bash
ufw allow 587/tcp
ufw allow 465/tcp
# port 25 ayrı: yalnızca MTA trafiği, gerekirse kaynak kısıtlı
Doğrulama ve gözlem
Yapılandırma değil, davranış test edilir. İki portun protokol farkını openssl ile gözlemleyin:
bash
# 587 — explicit: düz greeting görürsünüz, sonra STARTTLS ile yükselir
openssl s_client -starttls smtp -connect mail.evilmail.pro:587
# 465 — implicit: ilk byte'tan TLS, -starttls YOK
openssl s_client -connect mail.evilmail.pro:465
465'e -starttls smtp verirseniz handshake başarısız olur — bu, wrappermode'un doğru çalıştığının kanıtıdır. Uçtan uca kimlik doğrulamalı gönderimi swaks ile sürün; bayrak farkına dikkat:
syslog_name sayesinde iki portun log'da ayrıştığını doğrulayın (Debian/Ubuntu'da Postfix syslog'a yazar, çoğu kurulumda /var/log/mail.log):
bash
grep 'postfix/submission' /var/log/mail.log # yalnızca 587
grep 'postfix/smtps' /var/log/mail.log # yalnızca 465
Yalnızca journald kullanan bir sistemdeyseniz aynı ayrımı journalctl -t postfix/submission ve journalctl -t postfix/smtps ile yaparsınız.
Değişiklikleri devreye alırken postfix reload yeterlidir; restart şart değil ve mevcut bağlantıları koparır. Önce postfix check ile sözdizimini doğrulayın, sonra postconf -Mf çıktısının beklediğiniz -o setleriyle eşleştiğini gözden geçirin.
Yayına almadan önce kontrol listesi
TLS sertifika zinciri her iki portta da tam ve geçerli mi (openssl s_client çıktısında Verify return code: 0).
587'de smtpd_tls_security_level=encrypt, yani STARTTLS zorunlu.
SASL yalnızca TLS üzerinden teklif ediliyor (smtpd_tls_auth_only=yes).
smtpd_sender_login_maps + reject_sender_login_mismatch spoofing'i kesiyor; postmap ile .db güncel.
Rate limitler port bazlı ayrık (587 < 465) ve anvil zaman birimi biliniyor.
syslog_name iki portta farklı; log'da ayrışıyor.
Port 25'te SASL kapalı, relay kısıtlaması yerinde, açık relay yok.
postconf -M çıktısı beklenen üç servisi ve override setlerini gösteriyor.
postfix reload sonrası swaks smoke testi iki portta da geçti.
İki portu ayrı daemon, ayrı politika, ayrı log olarak kurduğunuzda gönderim yüzeyiniz artık tek bir parola sızıntısına açık değil. Bir istemci ele geçse bile yarıçapı, o portun güven sınırıyla sınırlı kalır — güvenlik mimarisinde aradığınız tam olarak budur.