disable_plaintext_auth Yalan Söylüyor: Dovecot'ta SASL Kimlik Doğrulamasını Doğru Sertleştirmek
disable_plaintext_auth = yes ayarı adının aksine PLAIN mekanizmasını kapatmaz; yalnızca şifresiz taşımada düz metin girişi reddeder. Taşıma katmanı ile mekanizma katmanını ayırıp Dovecot + Postfix üzerinde şifresiz parola sızıntısını gerçekten sıfırlamayı, SCRAM-SHA-256'nın gizli şema bedelini ve her adımı tcpdump/openssl ile kanıtlamayı anlatıyoruz.
EvilMail Team26 Temmuz 202612 dk okuma
Bir müşteri ticket açtı: "AUTH PLAIN'i kapattık ama parolalar hâlâ açık geçiyor." Konfigürasyonunda disable_plaintext_auth = yes yazıyordu, tıkır tıkır. Yine de 143 portunda alınan bir tcpdump çıktısında base64 kodlu kullanıcı:parola çifti apaçık görünüyordu. Bu bir bug değil; ayarın ne yaptığına dair yaygın bir yanlış anlamanın sonucu.
disable_plaintext_auth bir mekanizma anahtarı değildir. PLAIN veya LOGIN SASL mekanizmasını kapatmaz. Sadece şifrelenmemiş bir bağlantı üzerinden düz metin kimlik doğrulamasını reddeder. TLS tünelinin içinde PLAIN pekâlâ çalışmaya devam eder — ki olması gereken de budur. Sorun, "düz metin auth"un iki bambaşka şeyi kastetmesidir: parolanın telde korunmasız gitmesi ve parolanın mekanizma olarak challenge-response yerine olduğu gibi taşınması. Bu ikisini karıştırdığınız an ya güvenlik açığı bırakırsınız ya da çalışmayan bir kurulumla saatlerce boğuşursunuz.
Mail sunucu kimlik doğrulamasını iki bağımsız katman olarak düşünün:
Dovecot SASL Sertleştirme: disable_plaintext_auth ve Düz Metin Parolayı Kapatma — EvilMail Blog
Taşıma katmanı — hiçbir parolanın şifresiz bir soketten geçmemesi. Bunu disable_plaintext_auth, ssl = required ve Postfix'te smtpd_tls_auth_only sağlar.
Mekanizma katmanı — parolanın şifreli tünelin içinde bile olduğu gibi karşıya geçip geçmeyeceği. PLAIN geçirir; SCRAM-SHA-256 geçirmez.
Çoğu operatör için doğru mimari nettir ve bu makalenin savunduğu duruş budur: diskte hash'li parola, telde zorunlu TLS, PLAIN'i TLS ardında bırakmak. SCRAM'a ancak diskte cleartext saklamayı göze alabileceğiniz dar senaryolarda geçilir. Nedenini birazdan göreceğiz.
Sızıntı nerede oluşuyor: saldırı yüzeyi
Önce portları ve akışları döşeyelim, çünkü tehdit modeli buradan çıkıyor:
143 / 110 — düz IMAP / POP3, STARTTLS ile şifrelemeye yükseltilebilir ama başlangıçta açık.
993 / 995 — implicit TLS. Bağlantı ilk baytından itibaren şifreli.
587 — submission, STARTTLS ile.
465 — submissions, implicit TLS.
AUTH PLAIN'in içeriği base64'tür — bu bir kodlamadır, şifreleme değil. dXNlcjpwYXNz dizesini herhangi bir araç bir milisaniyede user:pass'a çevirir. Yani 143 üzerinde STARTTLS'e geçmeden yollanan bir LOGIN, ağı dinleyen herkese parolayı hediye eder.
Asıl sinsi tehdit STARTTLS-stripping'tir. Aktif bir ortadaki adam (MITM), sunucunun düz metin CAPABILITY yanıtından STARTTLS token'ını siler. İstemci artık STARTTLS'i "göremediği" için sessizce düz metne düşer ve parolasını açık soketten yollar. Bu yüzden "TLS'i destekliyoruz" demek yetmez; TLS'i zorunlu kılmanız gerekir. Sunucu, STARTTLS tamamlanmadan hiçbir kimlik doğrulama komutunu kabul etmemelidir.
Dovecot tarafı: üç ayar, üç farklı iş
Sertleştirmenin gövdesi üç ayarda toplanır ve her biri farklı bir işi görür. Bunları birbirine karıştırmamak, bu makalenin en pratik faydası.
/etc/dovecot/conf.d/10-auth.conf:
# Şifresiz bağlantıda düz metin girişi reddet.
# Varsayılan zaten "yes" ama açıkça yazmak niyetinizi belgeler.
disable_plaintext_auth = yes
# Sunulacak SASL mekanizmalarının listesi. TAŞIMAYLA ALAKASI YOK.
auth_mechanisms = plain login
/etc/dovecot/conf.d/10-ssl.conf:
# "yes" değil "required". required, STARTTLS tamamlanmadan
# hiçbir komuta izin vermez — STARTTLS-stripping'i öldürür.
ssl = required
ssl_min_protocol = TLSv1.2
ssl_prefer_server_ciphers = yes
Üç ayarın rolünü net ayıralım. disable_plaintext_auth şifresiz oturumda parola girişini yasaklar; bunun görünür sonucu, sunucunun şifresiz bir bağlantıda LOGINDISABLED capability'sini ilan etmesi ve AUTH=PLAIN reklamını gizlemesidir. ssl = required bir adım öteye geçer ve STARTTLS olmadan hiçbir komutu kabul etmez — yes ile required arasındaki fark tam olarak budur ve stripping saldırısını burada durdurursunuz. auth_mechanisms ise sadece hangi SASL mekanizmalarının müşteriye sunulacağını belirler; taşımanın şifreli olup olmadığıyla hiçbir ilgisi yoktur.
ssl_min_protocol için taban TLSv1.2'dir. TLSv1.0 ve 1.1, RFC 8996 ile 2021'de resmen kullanımdan kaldırıldı; 2026'da bunları hâlâ açık tutmanın tek sonucu denetim raporlarında kırmızı satırdır. TLSv1.3'ü tercih edin, 1.2'yi taban bırakın.
Postfix–Dovecot SASL köprüsü
Postfix kendi SASL implementasyonunu çalıştırmaz; kimlik doğrulamayı Dovecot'un auth soketine devreder. Bu köprü doğru kurulmazsa 587'de ya AUTH hiç çalışmaz ya da şifresiz oturumda parola kabul edilir.
Önce Dovecot tarafında soketi açın — /etc/dovecot/conf.d/10-master.conf, service auth bloğu:
service auth {
unix_listener /var/spool/postfix/private/auth {
mode = 0660
user = postfix
group = postfix
}
}
Sonra Postfix'te köprüyü bağlayın — /etc/postfix/main.cf:
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
# 587'de STARTTLS'ten ÖNCE AUTH ilan edilmez.
# Taşıma katmanının Postfix'teki karşılığı.
smtpd_tls_auth_only = yes
smtpd_tls_security_level = may
smtpd_sasl_security_options = noanonymous, noplaintext
smtpd_sasl_tls_security_options = noanonymous
Son iki satırdaki fark kritik ve sıkça yanlış yapılır. smtpd_sasl_security_options TLS dışında geçerlidir ve noplaintext ile düz metin mekanizmalarını yasaklar. smtpd_sasl_tls_security_options ise TLS içinde geçerlidir ve orada plaintext'e bilinçli olarak izin verir (noplaintext yoktur) — çünkü tünel zaten şifreli olduğundan PLAIN taşımak güvenlidir. İkisini eşitlerseniz ya TLS içinde gereksiz kısıtlama koyarsınız ya da TLS dışında kapıyı açık bırakırsınız.
Kurulumu tahminle değil postconf ile doğrulayın:
bash
postconf -n | grep -E 'sasl|tls_auth'
Düz metnin ötesi: SCRAM-SHA-256 ve şema gerilimi
Taşıma katmanını kapattınız; artık hiçbir parola şifresiz soketten geçmiyor. Peki tünelin içinde ne oluyor? PLAIN mekanizmasında istemci base64(\0kullanıcı\0parola) yollar ve sunucu parolanın tamamını görür. TLS bunu ağdan gizler ama sunucu tarafında düz parola bir an için bellekte belirir. Bearer-token modeli budur: doğru token'ı gösteren içeri girer.
SCRAM-SHA-256 challenge-response'tur. İstemci ve sunucu bir dizi kanıt (client-proof, server-signature) takas eder; parola telden hiç geçmez, sunucu da düz parolayı asla görmez. Sunucu verisinin sızması durumunda replay saldırısı belirgin biçimde zorlaşır.
Kulağa her zaman daha iyi geliyor — ama az konuşulan bir bedeli var. Dovecot'un SCRAM-SHA-256 veya CRAM-MD5 sunabilmesi için passdb'de parolayı cleartext ya da SCRAM-SHA-256 şemasında saklaması gerekir. Nedeni matematikseldir: challenge-response, sunucunun düz paroladan türetilmiş bir gizli değeri elinde tutmasını gerektirir. Parolayı SHA512-CRYPT veya BLF-CRYPT ile hash'lerseniz, Dovecot yalnızca PLAIN ve LOGIN üretebilir — çünkü tek yönlü hash'ten challenge kanıtı türetilemez.
İşte bilinçli seçim burada: daha güçlü mekanizma (SCRAM) ile diskte hash'li parola arasında ikisini birden alamazsınız. Tehdit modelinizi tartın. Çoğu operatör için disk sızıntısı riski, tel sızıntısı riskinden büyüktür — çünkü teli zaten zorunlu TLS ile kapattınız. Diskte cleartext parola tutmak ise bir veritabanı dökümünde tüm hesapları anında ele verir. Bu yüzden 2026'nın makul varsayılanı: diskte hash + telde zorunlu TLS + PLAIN'i TLS ardında bırakmak.
SCRAM'a yalnızca cleartext saklamayı gerçekten göze alabileceğiniz dar senaryolarda geçin (örneğin passdb'nin kendisi ayrı, sıkı korunan bir vault'ta ve disk sızıntısı tehdit modelinizde düşük). EvilMail altyapısında Dovecot şeması PLAIN'dir (uid/gid 5000) — bu SCRAM'ı teknik olarak mümkün kılar ama aynı zamanda diskte cleartext demektir ve teldeki TLS zorunluluğu bunu telafi etmez. Şema seçiminizi bu gerilimin bilinciyle yapın.
Submission (587) TLS ile başarılı, TLS'siz başarısız:
bash
swaks --server mail.evilmail.pro:587 -tls --auth PLAIN \
--auth-user [email protected]
# aynı komut -tls olmadan AUTH ilan edilmediği için başarısız olmalı
Canlı hata ayıklama için logu izleyin:
bash
journalctl -u dovecot -f | grep -i auth
Sertleştirme kontrol listesi
disable_plaintext_auth = yes — açıkça yazılı (varsayılan olsa bile).
ssl = required — yes değil required; STARTTLS-stripping'i kapatır.