# Securitate

Straturile de protecție ale platformei, de la izolarea firmelor în baza de date până la jurnalele care nu scriu niciodată un secret.

## Pe scurt

| Strat | Ce face |
| --- | --- |
| Izolarea firmelor | Row Level Security `FORCE` pe fiecare tabel cu `firma_id` |
| Acces declarat | fiecare rută își declară accesul; ruta nedeclarată răspunde `401 ruta_nedeclarata` |
| Sesiune | cookie `__Host-sesiune`, `HttpOnly`, `Secure`, `SameSite=Lax` |
| Gardă CSRF | scrierile cu cookie venite de pe alt site sunt refuzate cu `403` |
| Încadrare | `frame-ancestors 'self'` și `X-Frame-Options: SAMEORIGIN` pe orice răspuns |
| Parole | `scrypt` cu sare per cont, liste de parole comune refuzate, ultimele 5 parole nu se pot refolosi |
| Limite | 300 de scrieri pe minut pe sesiune, 1200 pe IP (vezi [Limite](#limite)) |
| Jurnale | cookie-ul, antetul `Authorization` și orice câmp `secret` sunt înlocuite cu `[ascuns]` |

## Izolarea firmelor

Fiecare cerere fixează firma activă în conexiunea la baza de date (`app.firma_id`). Politicile RLS sunt în mod `FORCE`, deci se aplică și proprietarului tabelului. O greșeală într-o interogare nu poate întoarce rândurile altei firme: baza de date pur și simplu nu le arată.

> [!NOTE]
> Tabelele cele mai sensibile (hash-urile parolelor vechi, sărurile) nu pot fi citite nici de utilizatorul bazei de date al aplicației. Verificarea se face prin funcții SQL care întorc doar „da” sau „nu”.

## Garda CSRF

Cookie-ul este `SameSite=Lax`, ca un link dintr-un email să te ducă direct în aplicație. Pentru scrieri există o gardă separată, aplicată înainte de orice rută:

```text title="Regula gărzii CSRF (metode POST, PUT, PATCH, DELETE cu cookie)"
Sec-Fetch-Site: cross-site                     → 403
fără Sec-Fetch-Site, cu Origin ≠ aplicația     → 403
fără cookie (aplicații, scripturi, MCP)        → trece; se aplică autentificarea rutei
```

## Parolele

- Hash `scrypt`, cu sare per cont; parola în clar nu se scrie nicăieri.
- Parolele din listele publice de parole sparte sunt refuzate la alegere.
- Parola nouă nu poate fi una dintre ultimele 5 ale contului.
- După a treia parolă greșită pe un cont real, proprietarul primește o alertă.
- Resetarea de către administrator închide toate sesiunile, acordurile OAuth și codurile de email ale contului.

## Antetele de securitate

```http title="Antete pe orice răspuns"
Content-Security-Policy: frame-ancestors 'self'
X-Frame-Options: SAMEORIGIN
```

O rută care își pune propriul `Content-Security-Policy` îl păstrează.

## Jurnalele

Jurnalele serverului ascund mereu, fără excepție configurabilă:

- antetul `Cookie` și antetul `Authorization`;
- orice câmp numit `secret`, până la trei niveluri adâncime în obiect (`secret`, `x.secret`, `x.y.secret`) și în corpul cererii;
- codul de invitație din cale (`/v1/invitatii/[cod]`).

## Raportarea unei probleme

Dacă găsești o vulnerabilitate, scrie administratorului platformei înainte de orice publicare. Nu testa pe datele altor firme.
