Segurança · Engenharia

JWT válido não significa acesso autorizado

Uma revisão de segurança no Salus mostrou por que autenticar um usuário não basta para autorizar o acesso a cada paciente e como transformar ownership em teste.

Uma revisão de segurança no Salus me levou a uma pergunta que continua existindo depois da autenticação:

este usuário pode acessar este recurso específico?

Imagine o seguinte cenário:

  1. O usuário A cria o paciente X.
  2. O usuário B faz login e recebe um JWT válido.
  3. B chama GET /patients/X.

Se a aplicação consulta apenas pelo patientId, B pode receber um paciente que pertence a A. B está autenticado, mas não está autorizado a acessar aquele objeto. Essa falha é conhecida como Broken Object Level Authorization (BOLA).

A autorização precisa chegar à consulta

Ter um JWT válido responde quem fez a chamada. A regra de acesso ainda precisa usar essa identidade para limitar o recurso consultado:

patientId + currentUser.id → recurso autorizado

Em vez de uma busca como:

findById(patientId)

a operação pode ser desenhada conceitualmente como:

findByIdAndOwner(patientId, currentUser.id)

O nome exato do método não é o ponto. O ponto é que o limite de acesso precisa fazer parte da regra e da busca, inclusive em leituras, alterações e exclusões.

O que responder quando o paciente pertence a outra pessoa?

Um 403 Forbidden pode indicar a B que o paciente X existe. Em contextos nos quais essa informação também é sensível, 404 Not Found pode ser a resposta preferível: para B, X não está entre os recursos que ele pode acessar.

Essa escolha depende da política da API, mas deve ser consistente. Ela reduz a possibilidade de usar respostas HTTP para testar quais IDs existem.

Segurança como comportamento verificável

A sequência não termina em login → JWT → middleware. Ela precisa chegar à operação sobre o objeto:

identidade → autenticação → autorização → ownership → acesso ao recurso

É essa propriedade que quero transformar em teste de regressão de segurança no Salus:

Usuário A cria o paciente X.
Usuário B tenta acessar X.
Resultado esperado: 404.

No Salus, as rotas de pacientes verificam o JWT e as operações são escopadas por ownerId. Quando um usuário tenta acessar o paciente de outra pessoa, a API retorna 404 nesse contexto. O teste de regressão reproduz o fluxo A cria X, B tenta acessar X e mantém essa propriedade verificável.

Segurança como comportamento verificável, não apenas configuração.

Projeto: Salus no GitHub

Voltar aos artigos