Iniciante Criptografia

Armazenamento seguro de senha

Nunca armazene senhas em texto puro. Nunca armazene apenas o hash MD5 ou SHA. A função de hash correta para senha é uma função de derivação de chave (KDF) lenta por design.

Por que MD5 e SHA não servem

MD5 e SHA-256 são rápidos — projetados para throughput alto. Uma GPU moderna calcula bilhões de hashes SHA-256 por segundo.

GPU RTX 4090:
  SHA-256: ~22 bilhões de hashes/segundo
  bcrypt (cost 12): ~2.800 hashes/segundo

Com MD5/SHA, um atacante que rouba o banco de dados testa senhas comuns em segundos via força bruta.

bcrypt

Algoritmo de 1999, ainda seguro. Inclui salt automático e fator de custo ajustável.

import bcrypt

# Hash de senha
senha = b"minha_senha_secreta"
hash_gerado = bcrypt.hashpw(senha, bcrypt.gensalt(rounds=12))
# $2b$12$... (salt + hash embutidos)

# Verificação
bcrypt.checkpw(senha, hash_gerado)  # True

O parâmetro rounds=12 define o custo (2^12 iterações). Aumente conforme o hardware evolui.

argon2

Vencedor da Password Hashing Competition (2015). Recomendação atual do OWASP. Três variantes:

  • Argon2d — resistente a GPU, mas vulnerável a side-channel.
  • Argon2i — resistente a side-channel, menos a GPU.
  • Argon2id — híbrido. Use este.
from argon2 import PasswordHasher

ph = PasswordHasher(
    time_cost=3,      # iterações
    memory_cost=65536,  # 64 MB de memória
    parallelism=2
)

hash_gerado = ph.hash("minha_senha")
ph.verify(hash_gerado, "minha_senha")  # True

O alto uso de memória torna ataques com hardware especializado (ASICs) inviáveis.

scrypt

Similar ao argon2 em conceito. Parametrizado por N (CPU/memória), r (tamanho de bloco) e p (paralelismo).

import hashlib, os

salt = os.urandom(16)
chave = hashlib.scrypt(b"senha", salt=salt, n=2**15, r=8, p=1)

Comparativo

AlgoritmoSalt autoResistência GPUResistência ASICRecomendação OWASP
MD5NãoFracoFracoNunca
SHA-256NãoFracoFracoNunca (para senha)
bcryptSimMédioMédioSim
scryptNãoBomBomSim
argon2idSimExcelenteExcelentePreferido

Regra de ouro

Ao verificar senha, compare sempre com função de tempo constante (checkpw, verify). Nunca compare strings diretamente — vulnerável a timing attack.