security: parse X-Forwarded-For from trusted proxies for rate-limit key

Resolves plan item A.1 (option б): login/setup rate-limiting used
RemoteAddr only, which behind the default reverse proxy is the proxy's own
address, making the limiter effectively global and enabling a lockout-DoS.
Now, when the request's direct peer matches the new TRUSTED_PROXY_CIDR list
(comma-separated CIDRs, env, empty by default), the last X-Forwarded-For
entry is used instead, giving a real per-client limit. Unset behaviour is
unchanged.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-15 23:53:59 +03:00
parent ee8d5f65d9
commit dca83e9671
8 changed files with 102 additions and 15 deletions
+7 -6
View File
@@ -26,12 +26,13 @@ func serveHTTP(ctx context.Context, cfg config, st *store.Store) error {
domains := domain.NewService(st, domain.NewOpenDKIM(cfg.opendkimDir), apps, cfg.dkimSelectorDef)
srvApp, err := web.New(st, domains, apps, web.Config{
Hostname: cfg.hostname,
CookieSecure: cfg.cookieSecure,
MailLogPath: cfg.mailLog,
DataDir: cfg.dataDir,
DBPath: cfg.dbPath,
Version: buildinfo.Version,
Hostname: cfg.hostname,
CookieSecure: cfg.cookieSecure,
MailLogPath: cfg.mailLog,
DataDir: cfg.dataDir,
DBPath: cfg.dbPath,
Version: buildinfo.Version,
TrustedProxyCIDRs: cfg.trustedProxies,
}, cfg.setupTokenPath)
if err != nil {
return err