Encryption at Rest and in Transit
Comprehensive guide to data security: Master TLS/HTTPS for data in motion and AES-256 for data at rest.
20+ years shipping large-scale distributed systems. Lessons pulled from things that broke in production.
- Encryption in transit uses TLS (HTTPS) to protect data moving between client and server — no one intercepting the network can read it
- Encryption at rest uses AES to protect stored data — no one with physical disk access can read it without the key
- Both are necessary — transit encryption alone does not protect against database breaches, and rest encryption alone does not protect against man-in-the-middle attacks
- Performance impact: TLS 1.3 adds ~5ms per handshake; AES-256 with AES-NI adds <1ms per field encryption
- Biggest mistake: relying solely on TDE (transparent encryption) and neglecting application-level encryption for high-risk fields like SSNs or API keys
Encryption scrambles your data so that only someone with the right key can unscramble it. Think of it like a locked box for your information. In transit encryption locks the box while it's being shipped across the internet. At rest encryption locks the box while it's sitting on a server or database. Both are needed because each protects against different kinds of theft.
In modern software architecture, 'secure by default' isn't just a catchphrase; it's a requirement. Encryption is the foundation of this security. Without transit encryption, any intermediary on the network—from a malicious Wi-Fi hotspot to a compromised ISP—can read your HTTP traffic in plaintext. Without rest encryption, a stolen database backup or a decommissioned hard drive exposes every user's PII (Personally Identifiable Information).
This guide moves beyond the theory. We will explore how TLS handshakes protect your packets in the wild and how to implement application-level encryption in Spring Boot to ensure that even if your database is fully compromised, your most sensitive fields remain indecipherable strings of noise. We'll also cover key management, compliance requirements, and the real production pitfalls engineers face when deploying encryption at scale.
Why Encryption at Rest and in Transit Is Not Optional
Encryption at rest protects data stored on disk or in databases, while encryption in transit protects data moving over a network. The core mechanic is cryptographic transformation: plaintext becomes ciphertext using an algorithm (e.g., AES-256 for rest, TLS 1.3 for transit) and a key. Without both, data is exposed at rest to physical theft or misconfigured storage, and in transit to packet sniffing or man-in-the-middle attacks.
In practice, at-rest encryption is transparent to the application — the storage layer encrypts pages or objects before writing to disk. In-transit encryption requires TLS termination at the load balancer or application server, with mutual TLS (mTLS) for service-to-service calls. Key management is the hard part: a leaked key or weak rotation policy undermines the entire scheme.
Use both for any system handling PII, financial data, or secrets. Compliance mandates (PCI DSS, HIPAA, GDPR) require it, but the real reason is defense in depth: a single misconfiguration — like an S3 bucket set to public — still leaks ciphertext, not plaintext. Encrypt everything, always.
Encryption in Transit — TLS/HTTPS
Encryption in transit ensures that data remains confidential and untampered while moving across the wire. Modern standards rely on TLS (Transport Layer Security) 1.2 or 1.3. When a client connects via HTTPS, a handshake occurs where the server proves its identity via a Certificate Authority (CA) and both parties negotiate a symmetric session key.
In a Spring Boot environment, you must ensure that your microservices don't just 'accept' HTTPS, but actively enforce it. This includes rejecting insecure algorithms (like SSLv3 or TLS 1.0) and ensuring that internal service-to-service communication is also encrypted, often managed via a Service Mesh like Istio or Linkerd.
TLS 1.3 reduces handshake latency to one round trip (0-RTT for resumption) and removes obsolete ciphers. In production, you should always prefer TLS 1.3 and enable HSTS to prevent SSL stripping attacks.
- The server shows its ID (certificate) via a trusted CA — you wouldn't hand a briefcase to a stranger.
- A symmetric session key is created using public-key cryptography (RSA or ECDHE) — the briefcase is locked with a shared secret.
- All data after handshake is encrypted with that session key — only the two parties can open the briefcase.
- TLS ensures integrity with MAC — if anyone tampers with the briefcase, the lock breaks and you know.
TLS 1.2 vs TLS 1.3 Comparison
TLS 1.3, finalized in 2018, is a major overhaul over TLS 1.2. It reduces handshake latency, removes obsolete and insecure cipher suites, and introduces 0-RTT (zero round-trip time) resumption. The following table compares key properties:
| Property | TLS 1.2 | TLS 1.3 |
|---|---|---|
| Handshake Round Trips | 2-RTT (full handshake) | 1-RTT (full handshake), 0-RTT for resumed sessions |
| Cipher Suites | Many combinations (RSA, DHE, ECDHE, AES-CBC, AES-GCM, ChaCha20) | Only 5 AEAD suites (TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384, TLS_CHACHA20_POLY1305_SHA256, etc.) |
| Key Exchange | RSA or Diffie-Hellman (DHE/ECDHE) | Only Diffie-Hellman (ECDHE) — RSA key exchange removed |
| Forward Secrecy | Optional (RSA key exchange does not provide it) | Mandatory — all key exchanges provide forward secrecy |
| Authentication | Certificate-based | Certificate-based, but signature algorithms are more restrictive |
| 0-RTT Resumption | Not supported | Supported (with anti-replay protection) |
| Supported Curves | Many (limited by implementation) | Only a few strong curves (P-256, P-384, P-521, X25519, X448) |
| Compression | Supported (but disabled in practice due to CRIME attack) | Removed entirely |
| Renegotiation | Supported | Not supported |
| Padding Extension | Not defined | Defined to prevent traffic analysis |
In production, you should enforce TLS 1.3 wherever possible. If legacy clients require TLS 1.2, ensure you only enable the strongest cipher suites (ECDHE with AES-GCM). Disable TLS 1.0/1.1 and SSLv3 entirely.
Encryption at Rest — Database and File Storage
Encryption at rest protects data stored on persistent media. There are two primary levels: Transparent Data Encryption (TDE) and Application-Level Encryption. TDE, offered by AWS RDS or Azure SQL, encrypts the entire database file on the disk. However, if a user gains access to the database via an SQL injection, TDE won't help because the database engine decrypts data for the authorized process.
For high-stakes data (like SSNs or API keys), we use Application-Level Encryption. Here, the data is encrypted before it ever hits the database driver. Even a root-level database admin cannot see the raw values without access to the keys stored in an external Secrets Manager like AWS KMS or HashiCorp Vault.
When implementing field-level encryption, pay attention to IV generation and key rotation. AES-GCM is the recommended mode because it provides authenticated encryption — it detects if data has been tampered with.
AES Encryption Modes Comparison (ECB, CBC, CTR, GCM)
AES operates on 128-bit blocks and can be used in different modes. The choice of mode dramatically affects security, performance, and features. Below is a comparison of the most common modes:
| Mode | Security | IV Required? | Authenticated? | Parallelizable? | Notes |
|---|---|---|---|---|---|
| ECB | Weak — same plaintext block always encrypts to same ciphertext block. Leaks patterns. | No | No | Yes | Never use ECB in production. |
| CBC | Secure if IV is random and unpredictable. Vulnerable to padding oracle attacks if not combined with MAC. | Yes (16 bytes) | No (can add HMAC) | No (sequential) | Requires PKCS#7 padding. Must MAC after encrypt. |
| CTR | Secure with unique IV/counter. No authentication. Parallel encryption and decryption. | Yes (nonce + counter) | No | Yes | Stream cipher mode — no padding needed. Must ensure IV is never reused. |
| GCM | Secure, provides authenticated encryption (confidentiality + integrity). Built-in MAC. | Yes (12 bytes recommended) | Yes | Yes (encryption and authentication) | The recommended mode for most applications. Hardware accelerated via AES-NI. Tag length 128 bits standard. |
GCM is the gold standard for symmetric encryption in production. It combines AES-CTR with a cryptographic hash (GHASH) to provide integrity verification. Always use GCM with a 12-byte random IV and never reuse the IV with the same key. Avoid ECB entirely. CBC can be used if authenticated separately (e.g., CBC + HMAC), but GCM is simpler and more performant.
Symmetric vs Asymmetric Encryption — Comparison
Encryption algorithms fall into two categories: symmetric (same key for encryption and decryption) and asymmetric (public/private key pair). Both are essential in modern cryptography. The table below contrasts them:
| Property | Symmetric Encryption | Asymmetric Encryption |
|---|---|---|
| Key Type | Single secret key | Public key (encrypt) + Private key (decrypt) |
| Speed | Very fast (hardware accelerated) | Slow (100-1000x slower than symmetric) |
| Key Size | 128–256 bits | 2048–4096 bits (RSA) or 256 bits (ECC) |
| Security Strength | 256-bit AES equivalent to 15360-bit RSA | Heavily relies on mathematical hard problems (factorization, discrete log) |
| Use Cases | Bulk data encryption (files, database fields, TLS session data) | Key exchange, digital signatures, certificate validation |
| Key Distribution | Must securely share the secret key | Public key can be freely distributed; private key kept secret |
| Examples | AES, ChaCha20, Twofish | RSA, ECDSA, Ed25519, Diffie-Hellman |
In practice, systems combine both: asymmetric encryption (RSA or ECDH) is used to exchange a symmetric session key, and then symmetric encryption (AES-GCM) is used for the actual data. This is called a hybrid cryptosystem. For example, TLS uses ECDHE for key agreement (asymmetric) and AES-GCM for bulk encryption (symmetric). For encryption at rest, we use symmetric encryption (AES) directly, but the encryption key is often wrapped (asymmetrically) using a master key in a KMS.
Key Management — The Hardest Part of Encryption
Encryption without proper key management is like locking a door and leaving the key in the lock. The security of your encrypted data ultimately rests on the secrecy and integrity of the encryption keys. This means you must never hardcode keys, never store them in the same database as the encrypted data, and never share them via email or chat.
Production-grade key management involves three principles: (1) Use a dedicated Hardware Security Module (HSM) or cloud Key Management Service (KMS) to generate, store, and rotate keys. (2) Implement key rotation policies — regularly generate new key versions and retire old ones. (3) Control access to keys with strict IAM policies and audit all usage.
Cloud providers offer managed KMS solutions (AWS KMS, Azure Key Vault, GCP Cloud KMS) that integrate seamlessly with their services. For multi-cloud or on-prem, HashiCorp Vault is a popular choice. A common pattern is envelope encryption: a master key (kept in the KMS) encrypts data keys, and the data keys encrypt your actual data. This allows efficient rotation of data keys without touching the encrypted payloads.
End-to-End Encryption (E2EE)
End-to-End Encryption ensures that data is encrypted on the sender's device and can only be decrypted on the intended recipient's device. No intermediary — including the server that facilitates the communication — can read the plaintext. This is different from TLS, which only protects data between the client and server; the server sees plaintext.
E2EE typically uses asymmetric encryption: each user has a public-private key pair. The sender encrypts the message with the recipient's public key, which can only be decrypted with the recipient's private key. In practice, for performance, a hybrid approach is used: a random symmetric key is encrypted with the recipient's public key, and the message is encrypted with that symmetric key.
Common applications include messaging apps (Signal, WhatsApp), email (PGP), and file sharing. Implementing E2EE in a web application is complex because the server never has access to the private keys — they must be stored client-side (e.g., in the browser's IndexedDB) and derived from a user password. This makes features like server-side search or server-side key rotation impossible without additional cryptographic techniques.
Application-Level Encryption Patterns in Spring Boot
Spring Boot applications often handle sensitive data that must be encrypted before persistence. A common approach is to create a JPA AttributeConverter that transparently encrypts and decrypts entity fields. This keeps encryption logic out of business code and ensures every read/write goes through encryption.
However, AttributeConverter has a significant gotcha: it runs inside the JPA transaction context. If encryption fails (e.g., KMS is unreachable), the entire transaction may roll back. Always handle encryption failures gracefully — consider storing an error marker or retrying with a fallback key. Also, note that AttributeConverter encrypts the column value, so any direct database queries or reports will see the ciphertext — you cannot query by plaintext directly without deterministic encryption.
For searchable encrypted fields, use deterministic encryption (AES-SIV) or a separate search index. Never use ECB mode. And remember: encrypting a field prevents indexing in most databases, so only encrypt fields that truly need it.
Encryption Performance Considerations
Encryption adds CPU overhead and latency, but modern hardware mitigates most of the impact. Key factors:
AES-NI Hardware Acceleration Most modern x86-64 processors (Intel Core i5/i7, Xeon, AMD Ryzen) include AES-NI instructions that accelerate AES encryption. With AES-NI, AES-256-GCM encryption/decryption runs at line rate (~1GB/s per core) with negligible CPU cost. Without AES-NI, software-based AES is still fast but can be 5-10x slower. Always verify AES-NI is enabled in your cloud instance type (e.g., AWS C5/m5 series have AES-NI; T2/t3.micro may not).
TLS Handshake Cost Establishing a new TLS connection involves asymmetric cryptography (key exchange) which is CPU-intensive. TLS 1.3 reduces the handshake from 2-RTT to 1-RTT (full handshake) and supports 0-RTT for resumption. The actual CPU cost of a full TLS 1.3 handshake is around 0.5-1ms on modern hardware (ECDHE key exchange). However, network round trips dominate latency — typically 5-30ms for a full handshake. Connection reuse (keep-alive, session resumption) eliminates this overhead.
Application-Level Encryption Overhead Encrypting a single database field with AES-GCM takes roughly 0.5-1µs per 1KB on a modern CPU with AES-NI. For a single API call encrypting 10 fields, total latency is <10µs — negligible compared to database round trips. The bigger cost is network round trips to KMS if you decrypt every time. Caching decrypted data keys locally (with proper expiry) reduces this.
Performance Best Practices 1. Enable AES-NI: ensure your deployment uses instances with AES-NI support (check /proc/cpuinfo or sysctl machdep.cpu.features on macOS). 2. Use TLS 1.3 and session resumption to minimize handshake overhead. 3. Cache KMS-decrypted data keys in local memory (with TTL). 4. For bulk encryption, use streaming encryption (e.g., CipherInputStream) to avoid large memory allocations. 5. Profile encryption overhead before optimizing — often encryption is not the bottleneck.
openssl speed -evp aes-256-gcm on a production server. If you see >500MB/s throughput, AES-NI is active. Rates below 50MB/s indicate software-only mode. Most cloud instances today enable AES-NI by default, but always verify in your environment.Compliance and Standards — PCI DSS, HIPAA, GDPR
Encryption isn't just a technical decision — it's a compliance requirement. Regulations like PCI DSS, HIPAA, and GDPR mandate encryption of specific data types. For example, PCI DSS Requirement 3.4 requires rendering PAN (Primary Account Number) unreadable anywhere it is stored, which typically means encryption, truncation, or tokenization. HIPAA's Security Rule requires encryption of ePHI (electronic Protected Health Information) at rest and in transit.
Meeting compliance requires more than just turning on encryption. You must demonstrate control over key management, prove that encryption is properly configured, and maintain audit logs of all encryption operations. Many compliance frameworks also require annual penetration testing and vulnerability scans that verify encryption configurations.
The key takeaway: encryption for compliance is often about process as much as technology. You need documented policies, access controls, and regular reviews. Tools like AWS Artifact and Azure Compliance Manager help maintain documentation, but the implementation must be correct at the code level.
Compliance Requirements Comparison Table
Regulations have specific but sometimes overlapping encryption requirements. The following table compares PCI DSS, HIPAA, and GDPR:
| Requirement | PCI DSS v4.0 | HIPAA Security Rule | GDPR |
|---|---|---|---|
| Data Scope | Cardholder data (PAN, CVV, track data) | Electronic Protected Health Information (ePHI) | Personal Data of EU residents |
| Encryption at Rest | Required (AES-128+ or equivalent) | Addressable (recommended with AES) | Encouraged as 'appropriate technical measure' |
| Encryption in Transit | Required (TLS 1.2+ or equivalent) | Required (TLS 1.2+ recommended) | Required for processing personal data |
| Key Management | Strict: key rotation, access control, dual control | Addressable: key management policies | Documented security measures |
| Algorithm Requirements | Approved algorithms (FIPS 140-2) | NIST-approved algorithms | Not specified but industry best practices |
| Audit Requirements | Annual assessment, quarterly scans | Risk analysis, periodic reviews | Data Protection Impact Assessment (DPIA) |
| Penalties | Fines up to $500k per violation | Up to $1.5M per violation | Up to 4% of global annual turnover |
| Tokenization Alternative | Allowed for PAN storage | Not typically used | Not specified |
Practical implications: If you store credit card data, you must comply with PCI DSS — this means using AES-256 for rest, enforcing TLS 1.2+ for transit, and implementing strict key management with rotation. For healthcare, HIPAA's addressable encryption means you must evaluate and decide; in practice, all covered entities encrypt ePHI. GDPR does not prescribe specific algorithms but expects encryption as part of 'data protection by design'.
Ciphertext Integrity – Why Your Encrypted Data Can Be Corrupted (And Nobody Tells You)
You encrypt a file. You store it. You decrypt it six months later and get garbage. Welcome to the world of bit flips, truncation, and padding oracle attacks. Encryption guarantees confidentiality, not integrity. That means an attacker (or a cosmic ray) can mutate your ciphertext in transit or at rest, and your decryption routine will cheerfully produce corrupted plaintext.
This isn't academic. In production, we've seen S3 buckets with silently corrupted AES-CTS ciphertext because someone's backup script did a partial overwrite. The result? Hours of debugging a 'decryption failure' that was actually a data corruption problem. The fix is to authenticate your ciphertext before you encrypt it. Authenticated Encryption with Associated Data (AEAD) modes like AES-GCM or ChaCha20-Poly1305 do this for you. They append a tag that verifies the ciphertext hasn't been tampered with.
Plain AES-CBC? You're vulnerable to padding oracle attacks. Just don't. If you must use a non-AEAD mode, pair it with HMAC-SHA256 over the ciphertext. Verify the HMAC before decryption. Every time.
The Wrecking Ball: Cryptographic Erasure vs. Deletion
You delete a database row. The file system marks it free. But the bytes are still on the SSD. In regulated environments (HIPAA, PCI-DSS), 'deleted' means unrecoverable. Logical deletion is a compliance trap. The only way to guarantee data erasure is to encrypt it and then throw away the key. That's cryptographic erasure.
Production pattern: encrypt every sensitive field with a unique data key (DEK). Store the DEK encrypted under a master key (KEK) in a KMS. When you need to 'delete' a record, just remove the encrypted DEK from your database. The ciphertext becomes gibberish. No waiting for garbage collection, no SSD wear-leveling headaches, no forensics recovery. Done.
This is how AWS S3 implements object deletion under the hood. They don't zero the bytes. They remove the key mapping. Your compliance auditor will love this because it's provable. The ciphertext exists, but without the key, it's entropy. Pair this with a short TTL on your KEK if you want paranoid-level assurance (e.g., Vault's lease mechanism).
API Gateway as the Cipher Chokepoint
Encryption in transit must terminate somewhere. When microservices handle TLS individually, you lose central control over cipher strength, certificate rotation, and protocol version enforcement. An API Gateway solves this by becoming the single TLS termination point. All external traffic hits the gateway, which decrypts, inspects, and re-encrypts before forwarding to internal services. This lets you enforce TLS 1.3, HSTS preloading, and mTLS for internal traffic without touching every service. The gateway also offloads costly asymmetric handshakes from application servers, improving latency. Why this order? First, decide the termination boundary (the gateway), then apply consistent cipher policies across all routes. Without a gateway, each team picks their own TLS config, creating weak links and audit nightmares.
Microsegmentation — Encrypting East-West Traffic
Encryption in transit focuses on north-south traffic (client to server), but the real risk is east-west traffic between microservices inside your cluster. Once an attacker breaches a single pod, they can sniff internal traffic if not encrypted. Microsegmentation forces every service-to-service call to use mTLS or an encrypted overlay (e.g., WireGuard, Istio sidecar proxies). The why: blast radius containment. Without it, a compromised auth service can read plaintext payment data flowing to the checkout service. The how: deploy a service mesh (Istio, Linkerd) that transparently injects TLS into every pod pair. Each sidecar handles mutual certificate verification, ensuring only approved identities communicate. This shifts encryption from a transport concern to a network policy — you define rules like “payment service can talk only to billing, on port 443, with mTLS.” The order: first model your service graph, then apply encrypted microsegments to each edge.
Missing Encryption at Rest Exposes 50 Million Records
- Disk-level encryption (TDE) does not protect data exported from the database.
- Encrypt sensitive fields at the application layer before writing to any external storage.
- Always assume that any export or backup is a potential leak — encrypt everything.
- Use Infrastructure as Code to prevent misconfigured buckets — don't rely on manual checks.
openssl verify -CAfile ca-cert.pem server.pem. Verify the certificate chain is complete and not expired.kms:Decrypt on the specific key ARN. Check network connectivity — KMS endpoint must be reachable (NAT gateway or VPC endpoint).openssl s_client -connect example.com:443 -servername example.com</code>curl -vI https://example.com/ 2>&1 | grep -i ssl</code>Key takeaways
Common mistakes to avoid
5 patternsHardcoding encryption keys in source code
Disabling SSL/TLS certificate verification in development and forgetting to re-enable in production
Using ECB mode for AES encryption
Not rotating encryption keys
Assuming TDE protects against SQL injection
Interview Questions on This Topic
Explain the 'Man-in-the-Middle' (MITM) attack and how TLS specifically prevents it.
Frequently Asked Questions
20+ years shipping large-scale distributed systems. Lessons pulled from things that broke in production.
That's Security. Mark it forged?
15 min read · try the examples if you haven't