pular para o conteúdo
voltar ao mapa
técnica
etapa: code
3 min de leitura

A04 Cryptographic Failures

A criptografia raramente é quebrada; ela é pulada, mal configurada ou mal usada. Transporte em texto puro, hashes de senha rápidos e chaves no código são como os dados realmente vazam.

testssl.sh / SSL LabsSemgrep crypto ruleslibsodiumage / KMS envelope encryptionHashcat (to test your own hashes)

O que é

Uma falha criptográfica é qualquer coisa que expõe dados sensíveis porque a criptografia estava ausente, fraca ou foi usada de forma incorreta: dados enviados sem TLS, senhas armazenadas com um hash rápido, segredos no código-fonte, tokens "aleatórios" previsíveis, algoritmos caseiros ou chaves que nunca são rotacionadas.

É o A04 no :2025. A primeira pergunta é sempre: quais dados são sensíveis, por onde viajam e onde ficam em repouso, e quem pode lê-los ali?

Como o ataque funciona

  • Sniffing de rede ou um ataque de downgrade lê o tráfego que não está protegido por TLS moderno.
  • O vazamento de um banco de dados entrega senhas com hash MD5 ou SHA-1 (ou sem salt); uma GPU quebra a maioria em horas.
  • Tokens construídos a partir de um timestamp ou de um gerador aleatório não criptográfico são previstos e forjados.
  • Uma chave commitada em um repositório, ou compartilhada por todos os clientes, decifra tudo de uma vez.
  • Modo ECB, nonces reutilizados ou criptografia sem autenticação permitem que o atacante identifique padrões ou modifique o texto cifrado.

Código vulnerável

Um hash rápido e sem salt para senhas e um gerador previsível para um token de redefinição.

auth.pypython
import hashlib, random

def store_password(pw):
    return hashlib.md5(pw.encode()).hexdigest()      # rápido e sem salt

def reset_token():
    return str(random.randint(100000, 999999))         # previsível
auth.jsjavascript
const crypto = require("crypto");

const storePassword = (pw) => crypto.createHash("sha1").update(pw).digest("hex");
const resetToken = () => Math.random().toString(36).slice(2);
Auth.javajava
String hash = DigestUtils.md5Hex(password);
String token = String.valueOf(new Random().nextInt(999999));

A correção

Use um hash de senha lento, com salt e feito para esse fim (, scrypt ou bcrypt) por meio de uma biblioteca mantida, e obtenha os tokens da fonte aleatória criptográfica do sistema operacional. Não invente algoritmos; não gerencie chaves brutas à mão se uma biblioteca ou um puder fazê-lo.

auth.pypython
import secrets
from argon2 import PasswordHasher

ph = PasswordHasher()

def store_password(pw):
    return ph.hash(pw)                    # salt e parâmetros já estão incluídos

def verify_password(stored, pw):
    try:
        return ph.verify(stored, pw)
    except Exception:
        return False

def reset_token():
    return secrets.token_urlsafe(32)      # 256 bits do CSPRNG do SO
auth.jsjavascript
const crypto = require("crypto");
const argon2 = require("argon2");

const storePassword = (pw) => argon2.hash(pw, { type: argon2.argon2id });
const verifyPassword = (stored, pw) => argon2.verify(stored, pw);
const resetToken = () => crypto.randomBytes(32).toString("base64url");
Auth.java (Spring Security)java
PasswordEncoder encoder = Argon2PasswordEncoder.defaultsForSpringSecurity_v5_8();
String hash = encoder.encode(password);
boolean ok = encoder.matches(password, hash);

byte[] raw = new byte[32];
new SecureRandom().nextBytes(raw);
String token = Base64.getUrlEncoder().withoutPadding().encodeToString(raw);
token.gogo
func ResetToken() (string, error) {
	b := make([]byte, 32)
	if _, err := rand.Read(b); err != nil { // crypto/rand
		return "", err
	}
	return base64.RawURLEncoding.EncodeToString(b), nil
}

Prove a correção

Teste propriedades, não algoritmos: dois hashes da mesma senha são diferentes (salt), o valor armazenado não é um simples hash rápido, os tokens são longos e únicos, e o transporte exige TLS moderno.

test_crypto.py (pytest)python
def test_hashes_are_salted_and_slow_format():
    a, b = store_password("correct horse"), store_password("correct horse")
    assert a != b                          # salt aleatório por hash
    assert a.startswith("$argon2id$")       # não é hex de md5/sha1
    assert verify_password(a, "correct horse")
    assert not verify_password(a, "wrong")

def test_reset_tokens_are_long_and_unique():
    tokens = {reset_token() for _ in range(1000)}
    assert len(tokens) == 1000
    assert all(len(t) >= 43 for t in tokens)   # 32 bytes, base64url
tls-check.shbash
# falhar se o servidor ainda aceitar protocolos legados
testssl.sh --protocols --quiet https://staging.example.com | tee tls.txt
! grep -E 'TLS 1(\.0|\.1)? .*offered' tls.txt

Checklist

  • Classifique os dados: saiba o que é sensível antes de escolher os controles.
  • TLS em todo lugar, apenas versões modernas, HSTS ligado; nenhum dado sensível em URLs.
  • Senhas: Argon2id, scrypt ou bcrypt com uma biblioteca mantida; nunca um hash rápido.
  • A aleatoriedade para segurança vem do do SO, nunca de Math.random ou random.
  • Use (AES-GCM, ChaCha20-Poly1305); nunca reutilize um nonce com a mesma chave.
  • As chaves ficam em um KMS ou gerenciador de segredos, são rotacionadas e nunca estão no repositório.
  • Não armazene o que não precisa; apague quando terminar.
OWASP Top 10A lista de referência mais famosa de riscos de segurança em aplicações web (A01 acesso quebrado, A02 falhas criptográficas, A03 injeção...), revisada a cada alguns anos pela comunidade OWASP. É um mapa educacional de categorias de risco — não um checklist de ferramenta nem uma certificação.ver no glossário →Argon2idUma função de hash de senhas com uso intensivo de memória e salt embutido. A lentidão é o objetivo: ela torna cada tentativa cara para o atacante.ver no glossário →KMSkey management serviceServiço gerenciado que cria, armazena e controla o uso de chaves criptográficas. A aplicação raramente toca a chave mestra: ela pede ao KMS para criptografar ou descriptografar, e o provedor registra cada uso em log auditável. Sem KMS, a chave acaba em disco e vira alvo.ver no glossário →CSPRNGgerador de números aleatórios criptograficamente seguroA fonte de bytes imprevisíveis do sistema operacional (secrets em Python, crypto.randomBytes em Node, crypto/rand em Go). Use-a para tokens e chaves, nunca Math.random.ver no glossário →Criptografia autenticadaAEADCriptografia que também detecta adulteração (AES-GCM, ChaCha20-Poly1305). Criptografia sozinha não impede que um atacante modifique o texto cifrado.ver no glossário →

conexões no mapa

atualizado em 14/10/2026 · fontes para aprofundar · reportar erro

em outros domínios

Estude antes

Desbloqueia

teste o que entendeu

Carregando perguntas…