# Security ## Model - **Devices** authenticate with Basic Auth (required by the protocol) - always behind TLS (reverse proxy). The password is verified by logging in to IMAP and is passed to SMTP/DAV only within the same request. It is never stored. The successful login cache keeps only HMAC-SHA256(login, password) with a random key generated at process start. - **The IMAP pool** keeps authenticated connections keyed by the same HMAC - a connection is only reused for a request with identical credentials. - **The panel** is a separate listener (loopback by default; another address requires explicit consent). Administrator passwords: argon2id. Session: random 256-bit token in an `HttpOnly; SameSite=Strict` cookie (`Secure` over HTTPS); only its SHA-256 is stored. Every modifying request needs the CSRF header. The first administrator can only be created with a one-time token from the CLI (valid 60 minutes). - **Panel headers:** strict CSP (`script-src 'self'`, no inline code), `X-Frame-Options: DENY`, `nosniff`, `Referrer-Policy: no-referrer`, COOP. ## Abuse protection - Lockout after `auth_fail_max` failures per account and `3x` per IP within the window; HTTP 429 with `Retry-After`. Other accounts from the same IP keep working until the IP limit is reached. - fail2ban friendly log line: `authentication failed user=jan@example.com ip=203.0.113.7 service=activesync` ```ini # /etc/fail2ban/filter.d/active-push.conf [Definition] failregex = authentication failed user=\S+ ip= service= journalmatch = _SYSTEMD_UNIT=active-push.service ``` - Panel: 5 failed logins in 10 minutes lock the IP for 15 minutes; constant verification cost even for unknown accounts. - Limits: request size (`sync.max_request_mb`), attachments, messages, WBXML depth and element count, IMAP response size, timeouts on every backend operation, HTTP header read timeout. - Unknown ActiveSync command names are counted as `Unknown` (no unbounded metric labels). - XML (Autodiscover, WebDAV) is parsed without DTD/entities (XXE, billion laughs). - The DAV client never follows `href`s to another host (SSRF). - Logins, device ids and device types are validated; SQL parameters are always bound. - `smtp.enforce_from` rewrites `From` to the account address; `Bcc` is stripped from the transmitted copy. ## Device control - Provisioning policies (password, encryption, camera, maximum mail age ...). Changing a policy invalidates keys - devices must accept the policy again. - Remote wipe (confirmed by typing the device id), device block, approval of new devices, mailbox block, blocked device types/User-Agents. - Every administrative action is written to the audit log (who, what, when, from where). ## systemd The service runs as `active-push` without privileges or capabilities, with `ProtectSystem=strict`, `ProtectHome`, `PrivateTmp`, `PrivateDevices`, `MemoryDenyWriteExecute`, a system call filter and write access only to `/var/lib/active-push`. The database is `0600`, the directory `0700`, `UMask=0077`. ## Recommendations 1. TLS only at the reverse proxy, with HSTS; ActivePush on `127.0.0.1`. 2. Panel through an SSH tunnel or VPN. If exposed - TLS + `panel.allowed_networks`. 3. SMTP submission with `reject_sender_login_mismatch`. 4. Enable `security.require_device_approval` in company environments. 5. Set a Prometheus token only if you scrape metrics; the endpoint then lives on the panel port. 6. `logging.log_wbxml` contains message content - only for short diagnosis.