Cryptographic Failures
Cryptographic failures (A02 in the 2021 OWASP Top 10, previously called "Sensitive Data Exposure") cover the ways sensitive data ends up unprotected: sent over plain HTTP, stored unencrypted, hashed with fast or broken algorithms, encrypted with misused primitives, or protected by keys that sit in source code. The consequences are leaked passwords, card numbers, health records, and tokens, plus regulatory penalties under GDPR, PCI DSS, and HIPAA.
The good news: almost all of these failures are avoided by a few principles. Classify your data, encrypt everything in transit, use high-level, well-reviewed libraries instead of assembling primitives, hash passwords with purpose-built algorithms, and manage keys in a KMS. The rule of thumb is simple: don't invent cryptography, and don't hand-wire it either.
TL;DR
- Classify data first: know which fields are sensitive and which regulations apply.
- Encrypt in transit everywhere: TLS 1.2+ externally and internally where networks aren't trusted, plus HSTS.
- Encrypt at rest with platform encryption (KMS-backed), and add field-level encryption for highly sensitive values.
- Passwords: Argon2id, scrypt, or bcrypt, never MD5, SHA-1, SHA-256, or unsalted hashes.
- Use authenticated encryption (AES-GCM, ChaCha20-Poly1305) via high-level libraries (libsodium, Tink, platform crypto). Never ECB, never reused nonces.
- Keys and randomness: keys in a KMS or secrets manager, rotated; cryptographically secure random generators for tokens.
Quick Example
Common failures and their fixes:
Core Concepts
Data in Transit
- Serve everything over HTTPS (TLS 1.2+/1.3), redirect HTTP, and enable HSTS. See Nginx TLS and HTTPS & TLS.
- Encrypt internal traffic where networks aren't fully trusted: database connections (
sslmode=verify-full), service-to-service calls (mTLS, service mesh), and message brokers. - Verify certificates. Disabling verification (
verify=False,rejectUnauthorized: false) turns TLS into security theater. - Don't send sensitive data in URLs (query strings end up in logs, browser history, and referrers).
Data at Rest
- Storage-level encryption (managed databases, disks, and object storage with KMS keys) protects against lost disks and some infrastructure compromises. It's usually on by default in clouds, so verify it.
- Application- or field-level encryption for especially sensitive fields (national IDs, bank details, health data): even database access or backups don't reveal plaintext without the key.
- Envelope encryption: data is encrypted with a data key, and the data key is encrypted by a master key in a KMS. It enables rotation and centralized access control.
- Don't store what you don't need: tokenize card numbers with a payment provider, and minimize and delete sensitive data. See PII handling and data retention.
Algorithms: What to Use and Avoid
Plan for crypto agility: record algorithm and version with ciphertexts and hashes, so you can migrate (for example toward post-quantum key exchange as standards and libraries mature).
Common Misuse
- Nonce/IV reuse with the same key in GCM or stream ciphers is catastrophic: it can reveal plaintext and forge messages.
- ECB mode encrypts identical blocks identically, leaking patterns.
- Encryption without authentication allows tampering (padding oracle attacks on CBC).
- Rolling your own protocols, "encoding" (Base64 isn't encryption), or custom hashing schemes.
- JWT pitfalls: accepting the
nonealgorithm, algorithm confusion (RS256 vs HS256), and weak HMAC secrets. See JWT.
Key Management
- Store keys in a KMS or HSM (AWS KMS, GCP KMS, Azure Key Vault, HashiCorp Vault), never in source code, images, or plain config.
- Separate keys by purpose and environment, rotate them regularly, and restrict and audit who and what can use them.
- Keep plaintext keys in memory only when needed, and never log them. See secrets management.
Best Practices
Use High-Level Libraries
Prefer APIs that make the right choices for you: libsodium/NaCl (crypto_secretbox, crypto_box), Google Tink, the cryptography package's recipes (Fernet, AEAD classes), and platform frameworks. They handle nonces, authentication, and safe defaults.
Hash Passwords Properly and Upgrade Over Time
Use Argon2id (or bcrypt) with parameters tuned to take tens to hundreds of milliseconds, and rehash on login when parameters change. See password security.
Encrypt Backups and Logs Too
Backups, exports, analytics copies, and logs often contain the same sensitive data with weaker protection. Apply the same encryption and access policies, and scrub secrets from logs.
Automate Detection
Use static analysis (Semgrep, CodeQL) for weak algorithms and hard-coded secrets, secret scanning in repositories, and TLS scanners for endpoints. Include cryptographic review in code review of security-sensitive changes.
Common Mistakes
Hard-Coded Keys and Secrets
Load keys from a KMS or secrets manager at runtime, and rotate any key that was ever committed.
Disabling Certificate Verification
Fix the trust configuration instead: install the internal CA bundle.
Treating Encoding or Hashing as Encryption
Base64 is reversible by anyone. Hashing isn't reversible, which is right for passwords and wrong for data you need back. Choose the primitive that matches the requirement.
FAQ
What's the difference between encryption and hashing?
Encryption is reversible with the right key and protects data you need to read later (messages, card data, files). Hashing is one-way: it produces a fixed digest you can compare against, but not reverse. Use it for integrity checks and, with slow password-hashing algorithms, for storing passwords.
Is SHA-256 okay for passwords?
No. SHA-256 is designed to be fast, so attackers with GPUs can test billions of guesses per second. Password hashing needs deliberately slow, salted, preferably memory-hard algorithms: Argon2id, scrypt, or bcrypt.
Do I need field-level encryption if my database is encrypted at rest?
Storage encryption protects against stolen disks and some infrastructure threats, but anyone with database access (including via SQL injection or leaked credentials) sees plaintext. Field-level encryption adds protection for the most sensitive fields, at the cost of complexity in querying and key management.
How should I generate API tokens and reset codes?
With a cryptographically secure random generator (secrets.token_urlsafe, crypto.randomBytes, SecureRandom), with enough entropy (128+ bits for long-lived tokens). Store only a hash of long-lived tokens, set expiration, and make them single-use where appropriate.
Related Topics
- OWASP Top 10 — The web application risk list
- Encryption — Cryptography fundamentals
- Password Security — Hashing and credential storage
- Secrets Management — Protecting keys and credentials
- HTTPS & TLS — Encryption in transit
- PII Handling — Minimizing and protecting personal data