57 lines
2.5 KiB
Markdown
57 lines
2.5 KiB
Markdown
# 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.
|