fix(security): corrige achados da varredura — render, brute-force, upload, WYSIWYG, cookie, sessões
1. /api/render: cap de 512 KiB na entrada (amplificação ~2× medida); decodeJSON agora amarra http.MaxBytesReader ao ResponseWriter (413 real ao cliente em todos os endpoints JSON) 2. Login com rate-limit por IP em memória (5 falhas/15 min → 429, acerto reseta, RemoteAddr puro — X-F-F não é confiável) + log de falha com IP 3. Upload: MaxBytesReader no corpo inteiro (64 MiB + 64 KiB) antes do parse do multipart; quota global de 2 GiB (MaxFilesTotalBytes) em AddFile 4. sanitizeRich neutraliza href/src com javascript:/vbscript:/data: (case/whitespace-insensível); link legítimo preservado 5. Cookie Secure passa a ser configuração explícita (NOTES_SECURE_COOKIE) — X-Forwarded-Proto é spoofável; documentado em .env.example e compose 6. Cookie agora carrega id de sessão opaco (crypto/rand 32B, TTL 30d, revogação no logout e no restart); token mestre só vale via Bearer — furo pego pelo próprio teste novo (token no cookie era aceito) Testes: rate-limit, revogação, canais separados, render 413, upload cap sw v16
This commit is contained in:
1 parent
1b9ce995ba
commit
6e0ec29888
20 files changed
+427
-53
No files matched your search
@@ -364,14 +364,21 @@ curl -sI -H "Authorization: Bearer $T" $B/api/files/static/<id> | grep -i dispos
|
||||
|
||||
## Segurança
|
||||
|
||||
- Token verificado em **tempo constante**; nunca é registrado nos logs.
|
||||
- Sessão do navegador em cookie **HttpOnly + SameSite=Lax** (mitiga CSRF); o token em
|
||||
`localStorage` foi preterido de propósito por ser exposto a XSS.
|
||||
- Token verificado em **tempo constante**; nunca é registrado nos logs. **Login tem rate-limit por
|
||||
IP** (5 tentativas erradas em 15 min → 429; acerto reseta; log de falha com IP).
|
||||
- Sessão do navegador em cookie **HttpOnly + SameSite=Lax** contendo um **id de sessão opaco**
|
||||
(`crypto/rand`, 32 bytes) — o token mestre nunca trafega em cookie. Logout **revoga** a sessão no
|
||||
servidor; reiniciar o processo revoga todas (relogin). O token mestre vale apenas via
|
||||
`Authorization: Bearer` (scripts/CLI).
|
||||
- **Cookie `Secure` é decisão de configuração** (`NOTES_SECURE_COOKIE=true` no `.env`), nunca de
|
||||
`X-Forwarded-Proto` do cliente (spoofável). Ative quando o acesso é sempre por HTTPS.
|
||||
- CSP restritiva (`default-src 'self'`), `X-Frame-Options: DENY`, `nosniff`; preview de HTML roda
|
||||
em iframe `sandbox` sem mesma origem; Markdown renderiza com HTML cru escapado.
|
||||
- Limite de 2 MiB por nota; corpo HTTP limitado a 4 MiB.
|
||||
- Rode atrás de TLS (reverse proxy) em produção — o cookie marca `Secure` automaticamente quando
|
||||
a requisição chega por HTTPS/`X-Forwarded-Proto`. O modelo é **token único compartilhado**
|
||||
em iframe `sandbox` sem mesma origem; Markdown renderiza com HTML cru escapado; o editor
|
||||
WYSIWYG neutraliza `href/src` com esquemas perigosos (`javascript:`, `vbscript:`, `data:`).
|
||||
- Limite de 2 MiB por nota; corpo HTTP limitado a 4 MiB; `/api/render` aceita no máximo 512 KiB de
|
||||
entrada (a conversão amplifica ~2×); upload limitado a 64 MiB **no corpo inteiro** e a
|
||||
**2 GiB de total** de anexos por instância (quota contra esgotamento de disco).
|
||||
- Rode atrás de TLS (reverse proxy) em produção. O modelo é **token único compartilhado**
|
||||
(sem usuários múltiplos); a imagem final é `scratch` non-root (uid 65534) — sem shell para
|
||||
`exec` de depuração, por design.
|
||||
- Preferências do editor e abas abertas ficam em `localStorage` (dados não sensíveis, por
|
||||
|
||||
Reference in new issue
Block a user