Skip to content

Security: monzeromer-lab/rust-api-starter

Security

docs/SECURITY.md

Security

Threat model summary

This template targets internet-exposed APIs that handle user authentication. It defends against the most common classes of attack for that shape of service:

  • Credential stuffing / brute force — argon2id password hashing (OWASP-recommended), rate limiting on /auth/login and /auth/register.
  • Password storage compromise — argon2id with per-user salts; a database leak yields hashes that are impractical to reverse at scale.
  • Session hijacking via stolen refresh tokens — refresh tokens stored as SHA-256 hashes, rotated on every use, with reuse detection that invalidates all outstanding tokens for the user.
  • JWT secret leakage — secrets required to be ≥ 32 chars; short secrets refuse to start. Rotate by redeploying with a new value (invalidates all sessions).
  • User enumeration/auth/login returns a generic 401 for both "unknown email" and "wrong password"; a dummy argon2 verify runs when the user doesn't exist to keep timing comparable.
  • SQL injection — all queries go through SQLx's parameter binding. No string concatenation into SQL anywhere in the codebase.
  • Cross-site request forgery — API responses set X-Content-Type-Options: nosniff, X-Frame-Options: DENY. CORS defaults to empty (no origins allowed). Operators opt in by setting CORS_ALLOWED_ORIGINS.
  • Cross-site scripting — the API returns JSON only; no HTML rendering attack surface.
  • Denial of service — per-IP rate limiting on auth endpoints. Graceful shutdown on SIGTERM with a 30-second drain window. Beyond that, rely on your load balancer and infrastructure provider.
  • Information disclosure in errors — 5xx responses never echo internal state or stack traces; the localized message is always stable. The locale field leaks which locales are supported (acceptable).

What this template does NOT defend against

  • Account takeover via email recovery — no password-reset flow is shipped. Build this in v2.1 with a separate email sender.
  • Phishing — out of scope; depends on user behavior and frontend.
  • Insider threats — the database user needs write access; no finer-grained access model.
  • Physical / network attacks on the host — operator's responsibility.
  • Targeted DDoS — rate limiting is per-IP and local; real DDoS mitigation requires a CDN or a purpose-built service.

Responsible disclosure

To report a security issue, please email <security-contact> (replace this before shipping). Do not open a public GitHub issue for security problems.

We aim to acknowledge reports within 72 hours and issue a fix within 14 days for confirmed vulnerabilities.

Operational checklist

Before putting this template in production:

  • JWT_SECRET generated from a CSPRNG (openssl rand -hex 32).
  • CORS_ALLOWED_ORIGINS set to the specific origins that should reach the API.
  • DOCS_ENABLED=false unless Swagger UI is intentionally public.
  • MIGRATE_ON_STARTUP=false on the long-running app; migrations run in a separate job.
  • Database connection uses TLS (managed providers do this by default).
  • TLS terminator (nginx/Caddy/load-balancer) in front; API does not speak TLS directly.
  • cargo audit clean; Dependabot PRs reviewed regularly.
  • Backup and restore rehearsed at least once.

Cryptography inventory

Purpose Algorithm Source
Password hashing argon2id argon2 crate, defaults
JWT signing HMAC-SHA256 jsonwebtoken crate
Refresh token hashing SHA-256 sha2 crate
Refresh token generation OS CSPRNG rand::rngs::OsRng
TLS (database, when enabled) rustls sqlx with rustls feature

There aren’t any published security advisories