Files
EMI-Backend/SECURITY_PASSWORD_PLAN.md
2026-02-20 20:20:40 -05:00

3.1 KiB

Password Security Hardening Plan

Scope

  • Applies to auth and password flows in:
    • index.js
    • auth/authEmail.js
    • mongoDB.js

1. Replace insecure reset flow with single-use token login

  • Problem:
    • Current flow resets by username and emails a plaintext temporary password.
  • Implementation:
    • Keep POST /resetPassword as token request endpoint:
      • Accept identifier (email/username).
      • Always return generic success response.
      • If account exists, create one-time login token with short TTL (15-30 min), store hashed token, email link.
    • Add POST /password/token-login:
      • Accept token.
      • Validate token (exists, not expired, unused), mark used atomically, then create normal auth session cookies.
    • Data model:
      • New collection password_login_tokens with fields:
        • userId, tokenHash, expiresAt, usedAt, createdAt, requestMeta.
      • Add TTL index on expiresAt.

2. Remove credential handling from GET/query

  • Problem:
    • /signup and /login accept GET and query params for credentials.
  • Implementation:
    • Change auth routes to POST only.
    • Read credentials from JSON body only.
    • Reject query-based credential inputs with 400.
    • Update Swagger docs and clients accordingly.

3. Add account-aware brute-force protection

  • Problem:
    • Only global IP limiter exists; auth endpoints are not sufficiently protected.
  • Implementation:
    • Add dedicated limiter middleware for auth endpoints (/login, /password/request-reset, /password/confirm-reset):
      • Combined key: normalized username/email + source IP.
      • Lower thresholds and progressive backoff/lockout window.
    • Add telemetry for blocked attempts.
    • Optionally store counters in Redis if horizontally scaled.

4. Prevent account enumeration

  • Problem:
    • API exposes different responses for unknown user vs wrong password.
  • Implementation:
    • Login: same response for invalid credentials regardless of user existence.
    • Reset request: always same response regardless of account existence.
    • Keep detailed reason only in internal logs/analytics.

5. Keep strong password hashing policy (clarify bcrypt behavior)

  • Problem:
    • Existing TODO comments incorrectly state bcrypt needs manual salt handling.
  • Implementation:
    • Keep bcrypt (or migrate to Argon2id in a separate change set).
    • Centralize hash policy:
      • cost factor (benchmark-backed; start at 12 if acceptable latency).
      • minimum password length and strength checks.
    • On login, detect outdated hash params and rehash after successful auth.

Suggested rollout order

  1. Tokenized login flow (new endpoint + DB token store).
  2. POST-only auth route enforcement.
  3. Generic auth/reset responses.
  4. Dedicated auth rate limiting.
  5. Hash policy tuning + opportunistic rehash.

Validation checklist

  • Unit/integration tests:
    • token creation, expiry, one-time use, invalid token paths.
    • login generic error response behavior.
    • auth rate limiter trigger and cooldown.
    • query credential rejection.
  • Manual:
    • verify no plaintext password emails are sent.
    • verify token cannot be reused after first successful consumption.