Executando verificação de segurança...
8

Segurança: Mensagens de erro genéricas VS específicas

Hoje me deparei com um vídeo do Lucas Montano do canal Lucas Montano em que ele fazia um react de um vídeo de um sênior que comentava sobre a preguiça de muitos programadores ao desenvolver sistemas.

Sabe aquela situação em que você preenche um formulário inteiro e ao clicar no bendito botão "salvar", ao invés de um retorno claro do problema, recebemos aquela clássica mensagem: “Erro ao salvar”? Então... mais ou menos sobre isso.

Mensagens de erro específicas

Lá no minuto 5:20 do vídeo, o Lucas Montano do canal Lucas Montano fala algo que me chamou a atenção:

“Tentar evitar ao máximo mensagens de erro genéricas… Sempre que a gente não detalha o erro pro usuário, a gente tá gerando trafego pro suporte, então sempre que o usuário ficou com uma dúvida ele vai entrar em contato com o suporte e suporte vai ser sempre um centro de custo pra empresa.”

Pois é… mensagens de erro genéricas, uma hora ou outra, vão se tornar um problema, seja pro cliente, pro suporte, pro dev ou, como na maioria dos casos, pra todos.

Quando o dev recebe uma tarefa mal escrita, ele acha ruim... mas faz o mesmo na hora de descrever mensagens de erro pro usuário.

Você não deve assumir que todos vão entender perfeitamente o funcionamento por trás de um campo cheio de validações e regras de negócio que você cuspiu no seu código hadouken.

Cansei de ver formulário com validação e retorno mais ou menos como nesse exemplo ai...

Mensagens de erro genéricas

Mas na hora me lembrei de uma situação. Há algum tempo trabalhei em algumas melhorias de vulnerabilidade de segurança em cima de um teste de intrusão (famoso Pentest) feito em uma API.

No endpoint de autenticação da API, eram retornadas mensagens de erro mais específicas, e, acredite se quiser, um dos pontos recomendados era justamente o uso de mensagens genéricas.

MAS COMO ASSIM?

Calma javascripto, vou explicar...

Se retornarmos mensagens de erro especificas em um método de autenticação como no exemplo que mencionei, podemos estar, na verdade, guiando um hacker numa tentativa de invasão a nossa API.

Se liga só...

Imaginem que num primeiro momento, ao tentar autenticar na nossa API todos os parâmetros enviados estão errados, então retornamos a mensagem de erro: “Sistema inválido”.

Exemplo de request com um sistema inválido

Exemplo de response com um sistema inválido

Um "bandindinho" poderia realizar um ataque de força bruta na API até conseguir descobrir um sistema válido.

Request 1: Tento sistema X
Request 2: Tento sistema Y
Request 3: Tento sistema Z

Após diversas tentativas, ele consegue fazer isso:

Exemplo de request com um sistema válido

Note que a mensagem de erro muda para: “Usuário inválido”.

Exemplo de response com um sistema válido

Logo, podemos assumir que o sistema é válido, o que indica que ele acertou o sistema.

"Opa, passei uma fase..." – pensa o hacker maligno nesse momento.

Assim, ele poderia repetir o processo com o parâmetro de usuário, até encontrar um válido:

Request 1: Tento usuário X
Request 2: Tento usuário Y
Request 3: Tento usuário Z

Exemplo de request com um usuário válido

Ao acertar um usuário, a mensagem de erro também muda, agora para: “Senha incorreta”.

Exemplo de response com um usuário válido

Agora era só repetir o processo para a senha ou então usar as informações de usuários descobertos para qualquer outra atividade maquiavélica, na tentativa de dominar a API… Muá-ha-ha-ha… Perdão, me empolguei…

O veredicto

Devo retornar mensagens de erro especificas ou genéricas?

Como toda boa resposta de dev sênior: depende!

Geralmente mensagens de erro genéricas vão apenas deixar o usuário perdido e sem saber o que fazer pra resolver um problema, ele vai acionar o suporte que muitas vezes também não sabe o que fazer pra resolver e o suporte vai acionar a área de TI pra você tentar entender o que significa aquela mensagem de erro debugando o código linguição que você escreveu e nem lembra mais. Por isso a importância de retornar mensagens de erro específicas.

Por outro lado, em alguns casos, como no exemplo que vimos, mensagens de erro específicas podem abrir brechas de segurança que nem imaginamos. Nesses casos, precisamos retornar mensagens de erro genéricas.

Escrevi esse artigo para compartilhar essa experiência, de repente você também nunca tinha pensado que uma simples mensagem de erro poderia se transformar em uma falha de segurança...

Me conta aí... você já tinha pensado por esse lado?

Carregando publicação patrocinada...
2

A preocupação do exemplo dado é válida, mas dá pra resolver com um simples rate limiting que vai acabar com qualquer brute force. Joga um delay de 50ms na resposta (login não precisa ser rápido) e acaba até com um bruteforce descentralizado.

2

Verdade Elias! Rate Limit é obrigação. Porém, penso que não resolve, mas sim, complementa.

Se além de um cachorro grande podemos colocar uma boa fechadura na porta, melhor ainda, não é?!

Hoje em dia infelizmente precisamos olhar pra qualquer possível brecha de segurança, se não, outra pessoa vai olhar hahaha.

2

Excelente ponto Filipe. Sua reflexão me trouxe à memória alguns sistemas de autenticação onde primeiro é inserido o login, e depois de validado é exibido o campo senha. Um clássico na security breach! Hahaha

Forte abraço!

2
2

Bom ponto, Elias! Acredito que não existe certo e errado, mas inúmeras variáveis no caminho kk'

No cenario Google, de certo existem N questões de bloqueio de segurança, log de tentativas... além é claro, de que é mais fácil encontrar um usuário que existe, do que um que não existe, no Google. E claro, o e-mail já é público, diferente do login de plataforma kk

Meu apontamento vai mais pro software de empresa XPTOEsquina, onde o login não é público, não tem base de usuário tão extensa, e muitas vezes, mal há um log de tentativas de login. O famoso, mundo real kkkk

1
2

E aí galera, achei a discussão fascinante e vou dar meus pitacos.
O que fica evidente é que a segurança digital é uma balança constante entre conveniência para o usuário e proteção contra ameaças. Segurança e usabilidade são como água e óleo, mas a gente precisa encontrar um meio termo. O rate limiting é uma boa ideia, mas como o Filipe mencionou, é apenas uma camada da segurança, não resolve tudo.

Também precisamos, por exemplo, pensar em como educar os usuários sobre segurança pq muitas vezes, ele é o elo mais fraco da segurança e não o sistema.

Concordo com o ponto sobre a diferença entre gigantes da tecnologia e empresas menores. Empresas como o Google têm recursos para investir em segurança de uma maneira que muitas empresas menores não têm, por isso é importante que as menores busquem soluções alternativas e se mantenham atualizadas sobre as melhores práticas.

Gosto muito dessas discussões, pragmáticas e diretas, sobre um tema que está em constante mudança. Agora me permitam mudar um pouco a frase do memorável Renato Russo, "Todos os dias quando acordo.... já estou desatualizado!