Aprenda / Segurança web

FundamentosAula 6 de 1617 min0% da trilha

Por que senha nunca é armazenada em texto puro (nem 'criptografada')

'A senha está criptografada no banco' é a frase mais comum e mais tecnicamente errada sobre segurança.

É comum ouvir "não se preocupe, a senha está criptografada no banco" — e essa frase, tecnicamente, está errada. O que protege senha não é criptografia, é hashing, e a diferença entre os dois não é só de vocabulário: ela muda o que é matematicamente possível fazer com o dado guardado.

Criptografia é reversível; hash não é

Criptografia (a mesma família de coisa usada em TLS, lição 14) é feita pra ser revertida por quem tem a chave certa — cifra e decifra, de propósito, porque em algum momento alguém legítimo precisa ler o conteúdo original de volta. Hashing é o oposto: é uma função de mão única. Dado um hash, não existe operação matemática que devolva a senha original — nem com a "chave certa", porque não existe chave nenhuma envolvida no processo.

o que existe (e o que não existe) pra reverter cada um
Criptografia:  texto_original --[chave]--> cifrado --[MESMA chave]--> texto_original
               (decifrar é uma operação válida e esperada)

Hashing:       senha --[algoritmo]--> hash
               (não existe "dehash" — a única forma de checar uma senha é
                gerar o hash de novo e COMPARAR os dois hashes)

É por isso que "esqueci minha senha" nunca resulta em receber a senha antiga de volta por e-mail — se um sistema faz isso, é sinal quase certo de que ele está guardando a senha de forma reversível (ou em texto puro), o que é uma falha grave. O fluxo correto de redefinição, sem nunca reexpor a senha antiga, é aprofundado na lição 12.

Como o login funciona, então, sem nunca "descriptografar" nada

No cadastro, o sistema gera o hash da senha digitada e guarda só o hash. No login, ele gera o hash da senha que acabou de ser digitada e compara os dois hashes — nunca olha pra senha original de novo, porque ela nunca ficou guardada em lugar nenhum.

pseudocódigo do login
# cadastro
hash_gerado = bcrypt(senha_digitada)
salvar_no_banco(hash_gerado)

# login (dias depois, sessão nova)
hash_da_tentativa = bcrypt(senha_que_a_pessoa_digitou_agora)
if hash_da_tentativa == hash_guardado_no_banco:
    login_permitido()
else:
    login_negado()

bcrypt é a família de algoritmo de hash desenhada especificamente pra senha — diferente de um hash genérico (como SHA-256, usado pra checar integridade de arquivo), bcrypt é deliberadamente lento, com um "fator de custo" configurável. Isso é uma escolha de design, não um defeito: um algoritmo rápido permitiria testar bilhões de senhas por segundo num vazamento de hashes; um algoritmo lento reduz isso a poucos milhares por segundo, tornando um ataque de força bruta contra o hash impraticável em escala.

Salt — por que duas senhas iguais não geram o mesmo hash

Se dois usuários usam a senha 123456 e o hash fosse gerado só a partir da senha, os dois teriam exatamente o mesmo valor salvo no banco — visível pra quem tiver acesso à tabela, e explorável em massa via rainbow tables (tabelas pré-computadas de hash de senhas comuns). O salt resolve isso: um valor aleatório, diferente pra cada usuário, é combinado com a senha antes de gerar o hash. Bibliotecas modernas de bcrypt já geram e guardam esse salt automaticamente junto do próprio hash — é por isso que duas senhas idênticas produzem hashes completamente diferentes no banco.

Senha em texto puro
id | email              | senha
1  | ana@exemplo.com    | 123456
2  | bruno@exemplo.com  | 123456   ← mesma senha, visível igual
Hash com salt (bcrypt)
id | email              | senha_hash
1  | ana@exemplo.com    | $2a$12$N9qo8uLOickgx2ZMRZoMy...
2  | bruno@exemplo.com  | $2a$12$K7bpZ1WdX3fJs9RyTmVeQ...  ← mesma senha, hash totalmente diferente

Um vazamento da tabela "ruim" expõe a senha de todo mundo instantaneamente. Um vazamento da tabela "boa" expõe só os hashes — um atacante ainda precisaria quebrar cada um individualmente, num processo caro por design, pra chegar na senha original.

Exercício

Um colega sugere: "em vez de bcrypt, vamos usar SHA-256 pra hash de senha — é o mesmo princípio e é bem mais rápido, então o login fica mais ágil". O que está errado nesse raciocínio?

Quiz rápido

Qual a diferença fundamental entre hashing e criptografia no contexto de senha?
Por que bcrypt é deliberadamente mais lento que um algoritmo de hash genérico como SHA-256?