Motivação
Manter um servidor de e-mail próprio vai muito além de simplesmente receber e enviar mensagens. Com o aumento de ataques de downgrade de TLS, spoofing e interceptação de tráfego SMTP, a adoção de padrões modernos como DANE, DNSSEC e TLSA deixou de ser opcional para quem leva segurança a sério.
O objetivo deste post é documentar o processo de hardening de um servidor de e-mail rodando Postfix 3.11 no FreeBSD, até atingir 100% no Internet.nl — com entrada no Hall of Fame.
Pré-requisitos
- Postfix 3.6+ (usamos 3.11)
- DNSSEC ativo no domínio (via Cloudflare, neste caso)
- Certificado EC-256 emitido via
acme.sh - OpenSSL 3.x
1. Certificado EC-256 com acme.sh
Certificados ECDSA (EC-256) são mais eficientes e seguros que RSA 2048. Para emitir via acme.sh:
acme.sh --issue --dns dns_cf -d mail.domain.tld --keylength ec-256
acme.sh --install-cert -d mail.domain.tld --ecc \
--cert-file /usr/local/etc/postfix/tls/cert.pem \
--key-file /usr/local/etc/postfix/tls/key.pem \
--fullchain-file /usr/local/etc/postfix/tls/fullchain.pem \
--reloadcmd "service postfix reload"
Atenção: O
acme.shcria o diretório com sufixo_eccpara certificados EC. Verifique o caminho correto em~/.acme.sh/mail.domain.tld_ecc/.
2. Configuração do Postfix (main.cf)
TLS para recebimento (smtpd)
# Certificado
smtpd_tls_cert_file = /usr/local/etc/postfix/tls/fullchain.pem
smtpd_tls_key_file = /usr/local/etc/postfix/tls/key.pem
# Protocolos — apenas TLS 1.3 para conexões obrigatórias
smtpd_tls_mandatory_protocols = >=TLSv1.3
smtpd_tls_protocols = >=TLSv1.2
# Ciphers
smtpd_tls_mandatory_ciphers = high
smtpd_tls_ciphers = high
smtpd_tls_exclude_ciphers = aNULL, CAMELLIA, SHA, ECDHE-ECDSA-AES256-CCM8, ECDHE-ECDSA-AES128-CCM8
smtpd_tls_mandatory_exclude_ciphers = aNULL, CAMELLIA, SHA, ECDHE-ECDSA-AES256-CCM8, ECDHE-ECDSA-AES128-CCM8
# Segurança
smtpd_tls_security_level = may
smtpd_tls_loglevel = 1
Nota:
smtpd_tls_prefer_server_ciphersnão existe no Postfix 3.6+. O parâmetrosmtpd_tls_fingerprint_digestjá ésha256por padrão a partir da versão 3.6.
TLS para envio (smtp) com DANE
# Protocolos
smtp_tls_mandatory_protocols = >=TLSv1.2
smtp_tls_protocols = >=TLSv1.2
# Ciphers
smtp_tls_mandatory_ciphers = high
smtp_tls_ciphers = high
smtp_tls_exclude_ciphers = aNULL, CAMELLIA, SHA, DHE
# DANE — valida o certificado do servidor remoto via TLSA + DNSSEC
smtp_tls_security_level = dane
smtp_dns_support_level = dnssec
smtp_tls_loglevel = 1
3. DANE e TLSA
O que é DANE?
DANE (DNS-Based Authentication of Named Entities) permite publicar no DNS informações sobre o certificado TLS do servidor, protegidas por DNSSEC. Isso impede ataques de downgrade onde um atacante remove o STARTTLS da negociação.
Gerando o registro TLSA
O tipo 3 1 1 (DANE-EE, SPKI, SHA-256) é o mais recomendado: vincula o hash da chave pública do certificado, e não muda enquanto a chave privada for a mesma — mesmo após renovações.
openssl x509 -in /usr/local/etc/postfix/tls/fullchain.pem \
-pubkey -noout | \
openssl pkey -pubin -outform DER | \
openssl dgst -sha256 -binary | \
xxd -p -c 32
O resultado é o hash a ser publicado no DNS:
_25._tcp.mail.domain.tld. IN TLSA 3 1 1 <hash_aqui>
Requisitos
- DNSSEC obrigatório no domínio do servidor de e-mail
- O registro TLSA deve estar no domínio do MX (
mail.domain.tld), não no domínio do e-mail (domain.tld)
Verificando
drill -D TLSA _25._tcp.mail.domain.tld
4. Removendo SHA-1 dos Signature Algorithms
O Internet.nl reporta os algoritmos de assinatura anunciados pelo servidor, não apenas os negociados. Por padrão, o OpenSSL anuncia ECDSA+SHA1 no TLS 1.2, mesmo que nunca seja usado na prática.
A solução é configurar o /etc/ssl/openssl.cnf globalmente.
Estrutura do openssl.cnf no FreeBSD
O arquivo já possui openssl_conf = openssl_init. Adicione ssl_conf na seção [openssl_init] e crie as seções necessárias:
[openssl_init]
providers = provider_sect
ssl_conf = ssl_sect # <-- adicionar esta linha
[ssl_sect]
system_default = system_default_sect
[system_default_sect]
CipherString = DEFAULT:@SECLEVEL=2
SignatureAlgorithms = ecdsa_secp256r1_sha256:ecdsa_secp384r1_sha384:ecdsa_secp521r1_sha512:rsa_pss_rsae_sha256:rsa_pss_rsae_sha384:rsa_pss_rsae_sha512:rsa_pkcs1_sha256:rsa_pkcs1_sha384:rsa_pkcs1_sha512
O que cada diretiva faz:
| Diretiva | Efeito |
|---|---|
CipherString = DEFAULT:@SECLEVEL=2 | Remove SHA-1, MD5, exige RSA >= 2048, desabilita compressão TLS |
SignatureAlgorithms | Restringe os algoritmos de assinatura anunciados no TLS 1.2/1.3 |
Importante:
CipherStringsozinho não é suficiente — é necessário definirSignatureAlgorithmsexplicitamente usando os nomes IANA (ex:ecdsa_secp256r1_sha256), não o formato legadoECDSA+SHA256.
Após editar, reinicie todos os serviços:
service postfix restart
service nginx restart
service dovecot restart
Verificando
testssl.sh --starttls smtp mail.domain.tld:25 2>&1 | grep "TLS 1.2 sig_algs offered"
Resultado esperado (sem SHA1):
TLS 1.2 sig_algs offered: ECDSA+SHA256 ECDSA+SHA384 ECDSA+SHA512
5. Rollover de certificado com DANE
Ao trocar o certificado (com nova chave privada), o hash TLSA muda. O procedimento correto é:
- Gerar o novo certificado (sem colocar em produção)
- Calcular o hash da nova chave:
openssl x509 -in /novo/cert.pem -pubkey -noout | \ openssl pkey -pubin -outform DER | \ openssl dgst -sha256 -binary | \ xxd -p -c 32 - Publicar dois registros TLSA no DNS (antigo + novo)
- Aguardar propagação (verificar TTL com
drill _25._tcp.mail.domain.tld TLSA) - Colocar o novo certificado em produção e reiniciar os serviços
- Remover o registro TLSA antigo
Regra de ouro: DNS primeiro, certificado depois. A ordem inversa causa rejeição de e-mails por servidores que validam DANE.
6. Resultado
Após todas as configurações seu servidor alcançará 100% no Internet.nl, com entrada no Hall of Fame.
✅ IPv6
✅ DNSSEC
✅ DMARC (p=reject) + DKIM + SPF (-all)
✅ STARTTLS + DANE válido
✅ TLS 1.3 + TLS 1.2 sem SHA-1
✅ Cipher suites seguras (ECDHE-ECDSA)
✅ RPKI
