Files
pargar/docs/security.md
T

57 lines
2.5 KiB
Markdown
Raw Normal View History

# Security
## Authentication and sessions
| Mechanism | Details |
|-----------|---------|
| Login | username/email + password + image CAPTCHA |
| Access JWT | Short-lived (~15 minutes) |
| Refresh | Hashed in DB; remember-me ≈ 30 days, short session ≈ 24 hours |
| Browser cookies | `pargar_access` / `pargar_refresh` — `HttpOnly`, `SameSite=Lax`, `Secure` when `PUBLIC_URL` is https |
| Frontend storage | Only `user` in `localStorage` (`pargar.auth`); tokens are not persisted |
| API | `credentials: "include"`; optional Bearer for tests/clients |
| Logout | Revoke refresh + clear cookies |
Public password recovery (`/api/auth/recovery/*` and `/recovery`) is disabled for students (404). Resets are admin-only and require the target account’s security answer.
## Secrets
- Outside `DEV_MODE`, `Validate()` rejects values like `change-me` / `local-dev-only` and JWTs shorter than 32 characters.
- Local Helm: generate-once; production: `existingSecret` required.
- `ADMIN_PASSWORD` only bootstraps when the admin user is missing; restarts do not overwrite the password.
## Proxy and CORS
- Only peers in `TRUSTED_PROXY_CIDRS` are trusted for `X-Forwarded-*` / `X-Real-IP`.
- CORS: `FRONTEND_ORIGINS` + `PUBLIC_URL` with `AllowCredentials: true`.
## Rate limiting
| Scope | Approximate behavior |
|-------|----------------------|
| Auth (login/register/captcha/refresh/recovery) | Redis per-IP budget; tighter after failures |
| Global `/api/*` | ~240 req/min/IP; 429 + user message + `Retry-After`; does not revoke tokens |
| External chat export | ~10/min/IP |
| Per-user uploads | Separately limited |
`/api/health` is excluded from the global ceiling.
## Uploads
| Type | Controls |
|------|----------|
| Admin video | Extension + MIME + magic (MP4/WebM) |
| Avatar | JPEG/PNG/WebP via magic only; client Content-Type is not trusted |
| Chat | Extension allow-list + sniff for image/video/audio/PDF/Office; raw public zip removed |
## Certificates and privacy
- Certificate URLs are unlisted; noindex via API, Traefik, Next, and robots.txt.
- Chat-export tokens are single-use, revocable, and redacted from logs/metric labels.
## Known trade-offs (current model)
- SameSite=Lax + same-origin instead of a separate CSRF token (adequate for this model; revisit if FE and API split domains).
- Donations and physical certificates have no online payment gateway — intentional.
- XSS remains dangerous; HttpOnly cookies reduce token theft from localStorage but do not eliminate XSS.