Skip to content

PAV-34: Hardening de segurança (rate limit, CORS, headers) - #250

Merged
Benevanio merged 3 commits into
Cla-Code-Community:developfrom
Jovinull:jovinull/pav-34-hardening-de-seguranca
Sep 7, 2026
Merged

Benevanio merged 3 commits into
Cla-Code-Community:developfrom
Jovinull:jovinull/pav-34-hardening-de-seguranca

Conversation

@Jovinull

@Jovinull Jovinull commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Descrição

Hardening de segurança da PAV-34, sobre o que já existia na develop. Levantamento completo do estado atual no comentário do card. Este PR fecha as lacunas independentes:

  1. Rate limit em POST /auth/register — os limiters já existiam mas eram aplicados só no POST /auth/login. Agora o cadastro usa authIpRateLimiter (por IP) + um novo authRegisterRateLimiter (por e-mail, bucket próprio, separado do de login) para conter criação de contas em massa e enumeração de e-mails.
  2. HSTS — securityHeaders passa a enviar Strict-Transport-Security: max-age=31536000; includeSubDomains sobre HTTPS (req.secure, resolvido via trust proxy) ou NODE_ENV=production. preload fica de fora de propósito — entrar na lista de preload é decisão difícil de reverter e deve ser opt-in do time.
  3. CORS fail-safe em produção — sem CORS_ALLOWED_ORIGINS, em production o fallback cai só nas origens *.candidate.app.br e loga um aviso; localhost nunca entra no allowlist de produção por fallback silencioso. Fora de produção o comportamento não muda.
  4. Documentação — seção Segurança do BACKEND.md reescrita (rate limiting com limites/env vars/cobertura, CORS, cabeçalhos completos, limites de entrada) + AUTH_RATE_LIMIT_* adicionadas ao .env.example da raiz. Fecha a AC "configurações de segurança ficam documentadas".

Fora do escopo (com nota)

  • Rate limit no endpoint de exportação (LGPD) — o endpoint não existe na develop, está na PAV-41 (feat(privacidade): exportar dados e excluir conta #240, em review). É follow-up de 2 linhas quando aquela mergear (ou vai no próprio PAV-41).
  • CSP / stored-XSS / sanitização de output — é a PAV-132.
  • Rate limiter global em todos os endpoints — o card pede "endpoints sensíveis", não compensa o risco de quebrar o dashboard.

Linear link

https://linear.app/candidateappbr/issue/PAV-34/hardening-de-seguranca-rate-limit-cors-headers-lgpd-basica

Como foi testado

Automatizado — npm run test --workspace=backend: 574/574 (+4 novos). Cobrem: HSTS presente com NODE_ENV=production e ausente sobre HTTP fora de produção; CORS em produção sem env bloqueia localhost e libera candidate.app.br; POST /auth/register retorna 429 com Retry-After após 5 tentativas para o mesmo e-mail.

Manual (stack local) — headers em GET /health: X-Content-Type-Options, X-Frame-Options: DENY, Referrer-Policy, Permissions-Policy presentes; HSTS ausente (dev/http, correto). POST /auth/register 6× para o mesmo e-mail: 201 → 409 × 4 → 429.

Checklist (LOCAL_DEVELOPMENT.md §14): instala do zero, app sobe, /health responde, testes do escopo passando, sem erro de TS no escopo, validado manualmente, sem regressão, logs limpos.

🤖 Generated with Claude Code

Jovinull and others added 3 commits September 3, 2026 23:55
Reusa authIpRateLimiter e adiciona authRegisterRateLimiter (bucket
próprio por e-mail, separado do de login) para conter criação de
contas em massa e enumeração de e-mails.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QchFWeX7puhd7ucw7ePyEW
- securityHeaders passa a enviar Strict-Transport-Security sobre HTTPS
  ou NODE_ENV=production (sem preload, opt-in do time).
- CORS: em produção sem CORS_ALLOWED_ORIGINS, cai só nas origens
  *.candidate.app.br e loga aviso; localhost nunca entra por fallback.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QchFWeX7puhd7ucw7ePyEW
Reescreve a seção Segurança do BACKEND.md com rate limiting, CORS,
cabeçalhos de resposta e limites de entrada; adiciona AUTH_RATE_LIMIT_*
ao .env.example da raiz. Fecha a AC de "configurações documentadas"
da PAV-34.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QchFWeX7puhd7ucw7ePyEW

@Benevanio Benevanio left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Status

⚠️ APROVADO COM RESSALVAS

Alerta

  • 🟡 MÉDIO — backend/src/middleware/cors.ts:32 — Quando CORS_ALLOWED_ORIGINS não está configurado em produção, o fallback adotado está correto. Porém, o logWarn é executado a cada requisição cross-origin, podendo gerar volume contínuo de logs em ambientes com tráfego elevado. Isso aumenta ruído e custo de observabilidade e pode dificultar a identificação de alertas realmente relevantes.

Sugestão: registrar esse aviso apenas uma vez durante a inicialização da aplicação ou memorizar o estado de configuração ausente, evitando emitir o mesmo alerta repetidamente a cada requisição.

Não considero este ponto bloqueante para o merge, mas recomendo tratá-lo para evitar ruído desnecessário nos logs de produção.

@Benevanio
Benevanio merged commit 4ed9d91 into Cla-Code-Community:develop Sep 7, 2026
1 check passed
@github-project-automation github-project-automation Bot moved this from Backlog to Done in JobAtlas – Kanban Sep 7, 2026
Benevanio added a commit that referenced this pull request Sep 28, 2026
…rd (#253)

## Release

Promoção da branch `develop` para `master`, consolidando 26 commits e 49
arquivos alterados.

## Objetivo

Disponibilizar em produção as entregas recentes de segurança,
versionamento da API, notas privadas por candidatura, melhorias no
dashboard e ajustes de confiabilidade/documentação.

## Escopo

Inclui as entregas das PRs `#234`, `#239`, `#242`, `#245`, `#246`,
`#250` e `#252`.

### API e documentação

- Adicionado o prefixo versionado `/api/v1` para os endpoints da API.
- Mantidas temporariamente as rotas sem prefixo para compatibilidade com
clientes existentes.
- Expandida a documentação OpenAPI/Swagger com schemas, respostas,
exemplos e endpoints principais.
- Atualizado o README com a estratégia de versionamento da API.

### Segurança

- Aplicado rate limit ao `POST /auth/register`, por IP e por e-mail.
- Endurecido o fallback de CORS em produção, sem permitir `localhost`
quando `CORS_ALLOWED_ORIGINS` não estiver configurada.
- Adicionado HSTS para tráfego HTTPS/produção.
- Aplicada CSP restritiva na API, frontend, painel administrativo, Nginx
e Vercel.
- Removido script inline de bootstrap do tema para compatibilidade com
CSP.
- Reforçada a renderização segura de descrições de vagas, bloqueando
atributos ativos, `iframe` e protocolos não permitidos.

### Candidaturas e dashboard

- Adicionado suporte a múltiplas notas privadas por candidatura.
- Criada a tabela `application_notes`, com migration, índices e remoção
em cascata.
- Disponibilizados endpoints autenticados para listar, criar, editar e
remover notas de vagas salvas.
- Garantido isolamento por usuário e ownership da vaga em todas as
operações de notas.
- Reorganizado o detalhe da candidatura com tiles para local,
modalidade, nível, fonte, salário e match.
- Removida a duplicação entre os dados principais e o bloco de detalhes
adicionais.
- Mantida compatibilidade com o campo legado de nota única para vagas
não rastreadas.

### Autenticação e confiabilidade

- Corrigidos tipos e fallbacks no envio de e-mail de boas-vindas.
- Validado `provider` como valor escalar antes da desconexão de contas
OAuth.
- Ajustado o timeout de teste de inicialização do servidor sob execução
completa da suíte.

### Documentação e fluxo de contribuição

- Adicionado template padrão de Pull Request.
- Atualizados `README.md`, `BACKEND.md` e `SECURITY.md`.
- Documentadas variáveis de ambiente de CORS e rate limiting.
- Registradas especificação, validação e handoff da PAV-92.

## Impacto de banco / migration

- [x] Altera schema e migrations.

Inclui a migration `0014_hard_korath`, que cria `application_notes` e
seus índices/foreign keys. A migration deve ser aplicada antes da
disponibilização do backend em produção.

## Impacto em contratos/API

- [x] Altera endpoint e comportamento de API.

A API passa a expor os endpoints em `/api/v1`. As rotas legadas sem
prefixo permanecem disponíveis temporariamente para evitar quebra
imediata de clientes.

Também foram adicionados endpoints de notas privadas em:

- `GET /saved-jobs/:id/notes`
- `POST /saved-jobs/:id/notes`
- `PATCH /saved-jobs/:id/notes/:noteId`
- `DELETE /saved-jobs/:id/notes/:noteId`

## Impacto de configuração / infraestrutura

- [x] Altera configuração de segurança.

A produção deve revisar:

- `CORS_ALLOWED_ORIGINS`
- `AUTH_RATE_LIMIT_IP_MAX`
- `AUTH_RATE_LIMIT_ACCOUNT_MAX`
- `AUTH_RATE_LIMIT_WINDOW_SECONDS`
- Headers CSP configurados em Nginx e Vercel

## Validação

As PRs de origem possuem cobertura automatizada para:

- Versionamento `/api/v1` e contrato Swagger.
- Rate limiting, CORS e HSTS.
- CSP e sanitização de conteúdo externo.
- CRUD e isolamento de notas privadas.
- Detalhe de candidatura e regressões de interface.
- Tipagem de autenticação e desconexão de provedores.

Também foram executados testes, lint e builds de backend/frontend nos
fluxos de origem.

## Riscos

- A aplicação de `0014_hard_korath` é obrigatória antes do deploy do
backend.
- Clientes devem migrar gradualmente para `/api/v1`; as rotas legadas
continuam disponíveis nesta etapa.
- CSP e CORS restritivos podem bloquear integrações externas não
declaradas.
- A PR está divergente de `master`; sincronizar a base com os dois
commits pendentes e revalidar os checks antes do merge.

## Rollback

O rollback pode ser realizado revertendo o merge da release.

Caso a migration já tenha sido aplicada, a reversão do código deve
preservar a tabela `application_notes` até que exista uma migration
reversa planejada, evitando perda de notas já criadas.

## Checklist final

- [x] Consolida entregas de `develop` para `master`.
- [x] Inclui alterações de API, banco, segurança, frontend e
documentação.
- [x] Mantém compatibilidade temporária com rotas legadas.
- [x] Possui migrations a serem aplicadas antes do deploy.
- [x] Sincronizar `develop` com os commits pendentes de `master`.
- [ ] Confirmar todos os checks da PR antes do merge.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants