A04 Cryptographic Failures
La criptografía rara vez se rompe; se omite, se configura mal o se usa mal. El transporte en texto plano, los hashes de contraseña rápidos y las claves incrustadas en el código son la forma en que los datos realmente se filtran.
Qué es
Una falla criptográfica es cualquier cosa que expone datos sensibles porque la criptografía faltaba, era débil o se usó de forma incorrecta: datos enviados sin TLS, contraseñas almacenadas con un hash rápido, secretos en el código fuente, tokens "aleatorios" predecibles, algoritmos caseros o claves que nunca rotan.
Es el A04 en el :2025. La primera pregunta siempre es: ¿qué datos son sensibles, por dónde viajan y dónde reposan, y quién puede leerlos ahí?
Cómo funciona el ataque
- El sniffing de red o un ataque de downgrade lee el tráfico que no está protegido por TLS moderno.
- La filtración de una base de datos entrega contraseñas con hash MD5 o SHA-1 (o sin salt); una GPU rompe la mayoría en horas.
- Los tokens construidos a partir de un timestamp o de un generador aleatorio no criptográfico se predicen y se falsifican.
- Una clave incluida en un commit de un repositorio, o compartida por todos los clientes, descifra todo de una vez.
- El modo ECB, los nonces reutilizados o el cifrado sin autenticación permiten que un atacante detecte patrones o modifique el texto cifrado.
Código vulnerable
Un hash rápido y sin salt para contraseñas y un generador predecible para un token de restablecimiento.
import hashlib, random
def store_password(pw):
return hashlib.md5(pw.encode()).hexdigest() # rápido y sin salt
def reset_token():
return str(random.randint(100000, 999999)) # predecibleconst crypto = require("crypto");
const storePassword = (pw) => crypto.createHash("sha1").update(pw).digest("hex");
const resetToken = () => Math.random().toString(36).slice(2);String hash = DigestUtils.md5Hex(password);
String token = String.valueOf(new Random().nextInt(999999));La corrección
Usa un hash de contraseñas lento, con salt y diseñado para ese fin (, scrypt o bcrypt) mediante una biblioteca mantenida, y obtén los tokens de la fuente aleatoria criptográfica del sistema operativo. No inventes algoritmos; no gestiones claves en bruto a mano si una biblioteca o un puede hacerlo.
import secrets
from argon2 import PasswordHasher
ph = PasswordHasher()
def store_password(pw):
return ph.hash(pw) # el salt y los parámetros ya están incluidos
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 del CSPRNG del SOconst 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");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);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
}Demuestra la corrección
Prueba propiedades, no algoritmos: dos hashes de la misma contraseña son distintos (salt), el valor almacenado no es un simple hash rápido, los tokens son largos y únicos, y el transporte exige TLS moderno.
def test_hashes_are_salted_and_slow_format():
a, b = store_password("correct horse"), store_password("correct horse")
assert a != b # salt aleatorio por hash
assert a.startswith("$argon2id$") # no es 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# fallar si el servidor todavía acepta protocolos heredados
testssl.sh --protocols --quiet https://staging.example.com | tee tls.txt
! grep -E 'TLS 1(\.0|\.1)? .*offered' tls.txtChecklist
- Clasifica los datos: sabe qué es sensible antes de elegir los controles.
- TLS en todas partes, solo versiones modernas, HSTS activado; ningún dato sensible en las URLs.
- Contraseñas: Argon2id, scrypt o bcrypt con una biblioteca mantenida; nunca un hash rápido.
- La aleatoriedad para seguridad sale del del SO, nunca de Math.random ni de random.
- Usa (AES-GCM, ChaCha20-Poly1305); nunca reutilices un nonce con la misma clave.
- Las claves viven en un KMS o gestor de secretos, se rotan y nunca están en el repositorio.
- No almacenes lo que no necesitas; bórralo cuando termines.
conexiones en el mapa
- A04 Cryptographic Failuresprotege las credenciales deA07 Authentication Failures
actualizado el 14/10/2026 · fuentes para profundizar · reportar un error
en otros dominios
- KMS & crypto - claves y envelopescloudsecclaves y cifrado gestionados, sin código propio
Estudia antes
Desbloquea
pon a prueba lo que entendiste
Cargando preguntas…