Repository navigation
Add connect-time abuse protection to the MX and MSA ports #409
Copy link
Copy link
Open
Labels
enhancementNew feature or requestNew feature or requestrealProven findingProven findingsecSecurity: exploitability, secrets, authorizationSecurity: exploitability, secrets, authorization
Description
What happened
Scanners and broken clients hit ports 25 and 587 continuously. Nothing blocks them or even counts them. Three Sentry issues (672, 198, and 5 events since late August) are peer failures after STARTTLS, with 0 users impacted.
- No connection limits, no DNSBL, no AUTH attempt limit (
SMTPHandler.handle_AUTH), and no recipient cap (MXHandler.handle_RCPT).command_call_limitis unset. - No attribution. aiosmtpd logs
session.peer, which behind Caddy is10.244.0.1. The real client IP exists only in the PROXY v2 header (services/email/proxy_protocol.py).handle_PROXYruns before the banner, so the app can act on it.
Constraints, verified
- caddy-l4 on TCP has no idle timeout (
idle_timeoutapplies to UDP only), no rate limiter, no SMTP matcher, and no pregreet test. Matchers see the first bytes only.remote_ipandclosework. - aiosmtpd
timeoutdefaults to 300 s, resets per command, and does not reset duringsmtp_DATA, so the message body counts against it. 32 MiB needs about 110 kB/s at 300 s.RELAY_PROXY_PROTOCOL_TIMEOUTis unset. - asyncio's 60 s
SSL_HANDSHAKE_TIMEOUTis not configurable through the aiosmtpd STARTTLS path. - postscreen fronts Postfix only. Greylisting delays mail. Spamhaus DQS is paid for commercial use. If proxy-level limits or timeouts are wanted later, CrowdSec, HAProxy, and nginx
streamare the outs.
Plan
- Measure. Log the real client IP at connect and count connections, STARTTLS failures, and AUTH failures per IP in Redis. The layer4 DEBUG logs give the same raw data without code.
- Close what is not SMTP. Use
@x httpand@x tlspluscloseon 25 and 587. Real clients wait for the banner and speak plaintext first, so HTTP and implicit TLS probes never reach the app. - Terminate idle sessions in aiosmtpd. Pick
timeoutfrom the slowest sender that we are willing to serve, and setRELAY_PROXY_PROTOCOL_TIMEOUT. - Add a connect guard in
handle_PROXY: per-IP caps and a deny set. Fail open on Redis errors. Log denials against the real client IP. - Add AUTH limits on 587.
- Only if needed, add CrowdSec with the firewall bouncer, or nginx or HAProxy in front for proxy-level limits and timeouts.
Non-goals
Filtering the STARTTLS failures themselves, since the client fails after the 220 banner, and greylisting.
Metadata
Metadata
Assignees
Labels
enhancementNew feature or requestNew feature or requestrealProven findingProven findingsecSecurity: exploitability, secrets, authorizationSecurity: exploitability, secrets, authorization
Projects
- StatusShow more project fieldsBacklog
Activity