Como armazenar senhas no banco de dados de forma segura

Como armazenar senhas no banco de dados de forma segura
guilherme-costa
guilherme-costa

Compartilhe

O uso de autenticação é praticamente unânime em qualquer aplicação. Seja um fórum, uma rede social, internet banking ou o sistema da empresa.

Ao desenvolver uma aplicação, precisamos tomar muito cuidado com o login e senha dos usuários. É comum encontrarmos tabelas como esta abaixo por aí, em vários sistemas:

Nome: Guilherme
Login: guicosta
Senha: **minha_senha_segura**

Nome: Luana
Login: luana_sc
Senha: **minha_senha_segura**
Banner da Escola de DevOps: Matricula-se na escola de DevOps. Junte-se a uma comunidade de mais de 500 mil estudantes. Na Alura você tem acesso a todos os cursos em uma única assinatura; tem novos lançamentos a cada semana; desafios práticos. Clique e saiba mais!

O que aconteceria com a reputação de nosso produto caso algum invasor tenha acesso a essa tabela com usuários e senhas?

“Oras, mas o banco de dados não é exposto na internet pública, fica em rede local”.

Será que isso é o suficiente? Em geral, as empresas que trabalham com desenvolvimento isolam os ambientes de desenvolvimento e produção. Inclusive, para as pessoas desenvolvedoras programarem, é comum usar um banco de dados com dados como email, telefone, etc. falsos, para garantir uma maior privacidade do usuário final.

Mas, estes dados ainda são visíveis para administradores de sistemas e o time de infraestrutura. E se algum funcionário, buscando prejuízo da empresa, executar um select * from Usuarios e publicar estas informações?

Moral da história: nunca guardar uma senha bruta no banco de dados!

Se não vamos guardar a senha em formato bruto, o que podemos fazer? Podemos guardar um texto bagunçado difícil de reconhecer. Algo como:

Nome: Guilherme
Login: guicosta
Hash da Senha: 
4f24ed619ffb73b8792e3f74e5ffa3bb

Nome: Luana
Login: luana_sc
Hash da Senha: de1dc74c5561739cbe4c6368f78e9b6f

O nome disso é hash! Uma função que gera o hash recebe como entrada um texto qualquer, e o mapeia para uma cadeia de caracteres com tamanho fixo. Por exemplo:

  • Hash de "minha_senha_segura" = 4f24ed619ffb73b8792e3f74e5ffa3bb;
  • Hash de "sp23494" = de1dc74c5561739cbe4c6368f78e9b6f;

A partir de de1dc74c5561739cbe4c6368f78e9b6f é inviável descobrir a senha original!

Mas, peraí, o usuário ao fazer login não vai digitar esse código gigante, né? Na verdade, quando recebemos uma requisição de autenticação, o código da aplicação irá calcular o hash da senha informada e comparar com o que está no banco de dados!

Desta forma, iremos comparar hashes e não mais senhas brutas, nos poupando do problema de guardar esta informação sensível no banco de dados.

Mas…Será que isto está seguro mesmo? As pessoas que conseguirem acesso a esta tabela não poderão saber qual senha é qual, mas poderão calcular o hash das senhas mais usadas no mundo, como abcdef ou 123456:

  • Hash de "abcdef" = e80b5017098950fc58aad83c8c14978e;
  • Hash de "123456" = e10adc3949ba59abbe56e057f20f883e;

Se fizermos uma busca em nossa tabela pelos usuários que possuem esses hashes, saberemos quem possui a senha abcdef ou 123456! Ops, nada bom, né? E se não calcularmos mais os hashes nos baseando apenas na senha bruta, mas a concatenando com algo mais? Dessa forma, não calcularemos o hash do texto abcdef e sim o hash do texto abcdef + <Texto aleatório>. Por exemplo: abcdef+HjJK8L. Teremos um hash totalmente diferente!

Mas, isto só vale se houver um texto aleatório diferente para cada usuário, senão nosso invasor poderá calcular o hash das senhas mais comuns com este mesmo texto aleatório.

Essa porção a mais que colocamos na senha antes de calcular o hash se chama salt! Então nossa tabela de usuários será:

Nome: Salt Guilherme
Login: guicosta
Hash da Senha: 
2bcc9ee9b953cd813008f18f7748656
37hsis2m

Nome: Luana
Login: luana_sc
Hash da Senha: 6da49cd9bc606d9bcdb141cd9364e145
83nc0m20

Se houver informações internas vazadas, será difícil manter a segurança total. Mas, com esse gerenciamento de senhas mais robusto, podemos dificultar ao máximo que pessoas mal-intencionadas tenham acesso a informações sensíveis.

Talvez você esteja pensando que melhor que isso só se guardarmos as senhas criptografadas. Será?

A criptografia, por definição, deve ser reversível! A partir da chave de criptografia e do texto cifrado, voltaremos ao texto original, ao contrário do hash, em que não podemos voltar ao texto original.

Se nossa tabela de senhas cair em mãos erradas, será necessário apenas descobrir a chave de segurança. Uma chave fraca pode ser obtida com força bruta e uma chave forte ainda precisa ser armazenada e visível para alguma pessoa, não? E se essa pessoa usar ou compartilhar a chave com alguém? É por isto que usamos hash e salt!

Gostou de ver um pouco sobre segurança e algumas vulnerabilidades que podem existir na aplicação? Na Alura, falamos mais sobre segurança no curso Segurança Web: Vulnerabilidades do seu sistema e OWASP. Temos também este artigo do que fala sobre como implementar os recursos de Hash.

Veja outros artigos sobre DevOps