Na década de 90, a maioria das aplicações web armazenava senhas dos usuários em texto puro (plain text) no banco de dados. Isso se tornou um grande problema com a popularização de ataques como SQL Injection, que permitiam a hackers acessar essas senhas diretamente. Além disso, como as pessoas reutilizavam senhas em vários serviços, um único vazamento comprometia a segurança dos usuários em diversos lugares.
Como primeira solução, o mercado passou a usar algoritmos de hash como MD5 e SHA-1. Esses algoritmos são determinísticos, possuem efeito avalanche e são unidirecionais. No entanto, eles são extremamente rápidos (bilhões de hashes por segundo), o que permite ataques de pré-computação, como o uso de rainbow tables — listas gigantescas de senhas já convertidas em hash, geradas a partir de vazamentos reais, como o da RockYou em 2009.
Para dificultar esses ataques, introduziu-se a técnica de salt (um valor aleatório concatenado à senha antes do hash). Isso resolve o problema de senhas iguais gerarem hashes iguais e inviabiliza o uso direto de rainbow tables, pois o hacker precisa recalcular os hashes para cada salt. Porém, a alta velocidade do MD5 e SHA ainda permite que o hacker brute force as senhas mesmo com salt, usando poder computacional paralelo.
A evolução seguinte foi o uso de algoritmos CPU-hard, como o Bcrypt, que são propositalmente lentos. O Bcrypt utiliza um fator de trabalho (custo) que dobra o tempo de hash a cada incremento. Com um custo 12, por exemplo, gera-se apenas cerca de 3 hashes por segundo. Isso reduz drasticamente a velocidade de ataques de força bruta, tornando inviável testar bilhões de combinações por linha do banco de dados.
No entanto, o Bcrypt tornou-se vulnerável ao paralelismo massivo com GPUs, que possuem milhares de núcleos. Uma GPU como a RTX 5090 pode testar dezenas de milhares de hashes por segundo, reduzindo o tempo de ataque de anos para dias. Por isso, o Bcrypt deixou de ser considerado totalmente seguro, especialmente contra ataques com hardware especializado.
A solução atual e mais segura é o algoritmo Argon2, vencedor do Password Hashing Competition. Ele é memory-hard, ou seja, exige grande quantidade de memória RAM para gerar o hash — algo que GPUs têm em quantidade limitada. No Argon2, é possível configurar memória (ex.: 64 MB), iterações e paralelismo. Isso trava ataques baseados em GPU, pois cada tentativa consome muita memória, impedindo a execução massiva em paralelo.
Por fim, recomenda-se ainda o uso de pepper — um valor secreto armazenado fora do banco de dados (ex.: no ambiente da aplicação), que é concatenado à senha antes do hash. Mesmo que o banco de dados vaze com salts, custos e hashes, sem o pepper o hacker não consegue recriar o hash original. A combinação de Argon2 + pepper representa o estado da arte atual para armazenamento seguro de senhas, exigindo conhecimento profundo de paralelismo, memória e funcionamento de hardware.