Encryption at Rest and in Transit: Implementation Patterns
Encryption protects your data from exposure, but the implementation details matter enormously. Here's how to get encryption right for storage and network traffic.
Strategic Systems Architect & Enterprise Software Developer
Encryption at Rest and in Transit: Implementation Patterns
Encryption is the mechanism that ensures data remains confidential even when it falls into the wrong hands. A stolen hard drive, an intercepted network packet, a compromised backup — without encryption, any of these produces a data breach. With proper encryption, the attacker has ciphertext that is computationally infeasible to decrypt.
But "use encryption" is not a strategy. The implementation details — which algorithms, which key management approach, which layers — determine whether your encryption actually protects data or merely provides a false sense of security.
Encryption at Rest
Encryption at rest protects data stored on disk — databases, file systems, backups, and object storage. There are two common approaches: full-disk encryption and application-level encryption.
Full-disk encryption encrypts the entire storage volume. Every byte written to disk is encrypted; every byte read is decrypted transparently. The operating system or storage layer handles this without your application knowing. LUKS on Linux, BitLocker on Windows, and cloud provider volume encryption (AWS EBS encryption, GCP disk encryption) are all full-disk encryption implementations.
Full-disk encryption protects against physical theft of the storage media. If someone steals a server's hard drive or gains access to the raw disk image, they cannot read the data without the encryption key. It does not protect against logical access — a compromised application running on the server has full access to the decrypted data because the operating system transparently decrypts it.
Application-level encryption encrypts specific data fields before storing them. Your application encrypts a social security number, a credit card number, or a medical record before writing it to the database. Even if the database is compromised — through SQL injection, a leaked backup, or a compromised database credential — the encrypted fields remain unreadable without the application's encryption keys.
import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
Const ALGORITHM = "aes-256-gcm";
Function encrypt(plaintext: string, key: Buffer): EncryptedData {
const iv = randomBytes(16);
const cipher = createCipheriv(ALGORITHM, key, iv);
const encrypted = Buffer.concat([
cipher.update(plaintext, "utf8"),
cipher.final(),
]);
const authTag = cipher.getAuthTag();
return {
ciphertext: encrypted.toString("base64"),
iv: iv.toString("base64"),
authTag: authTag.toString("base64"),
};
}
Function decrypt(data: EncryptedData, key: Buffer): string {
const decipher = createDecipheriv(
ALGORITHM,
key,
Buffer.from(data.iv, "base64")
);
decipher.setAuthTag(Buffer.from(data.authTag, "base64"));
return decipher.update(data.ciphertext, "base64", "utf8") + decipher.final("utf8");
}
Use AES-256-GCM for application-level encryption. GCM provides authenticated encryption — it protects both confidentiality and integrity, meaning an attacker cannot decrypt the data and cannot modify it without detection. Never use ECB mode. Never use CBC without HMAC authentication. These are not academic concerns — they represent real attack vectors that have been exploited in production systems.
For a broader overview of encryption fundamentals, see the data encryption guide.
Encryption in Transit
Encryption in transit protects data moving between systems — from a user's browser to your server, between microservices, from your application to the database, and between data centers.
TLS (Transport Layer Security) is the standard for encrypting network traffic. Every HTTP connection should use TLS (HTTPS). Every database connection should use TLS. Every internal service-to-service connection should use TLS. There is no legitimate reason to send data in plaintext over any network, including internal networks.
Configure TLS correctly. Use TLS 1.2 or 1.3 — disable TLS 1.0 and 1.1. Use strong cipher suites and disable weak ones. Enable HSTS (HTTP Strict Transport Security) to prevent downgrade attacks. The SSL/TLS best practices guide covers the specifics of TLS configuration in detail.
Mutual TLS (mTLS) adds authentication to the encryption. Standard TLS verifies the server's identity to the client. MTLS also verifies the client's identity to the server. Both sides present certificates and both sides verify them. This is the standard for service-to-service communication in zero-trust architectures, ensuring that only authorized services can communicate with each other.
End-to-end encryption extends protection through intermediary systems. Standard TLS encrypts data between two endpoints, but if your data passes through a load balancer, API gateway, or message queue, it is decrypted and re-encrypted at each hop. End-to-end encryption encrypts data at the source and decrypts it only at the final destination, preventing intermediary systems from accessing the plaintext.
Key Management
Encryption is only as strong as your key management. The best algorithm in the world is worthless if your encryption key is hardcoded in your source code, committed to Git, or stored in plaintext on the same server as the encrypted data.
Never store encryption keys alongside encrypted data. If an attacker compromises your database and your encryption keys are in a configuration file on the same server, the encryption provided zero protection. Use a dedicated key management service — AWS KMS, Google Cloud KMS, HashiCorp Vault, or Azure Key Vault — that stores keys separately from the data they protect.
Implement key rotation. Encryption keys should be rotated on a regular schedule and immediately if a compromise is suspected. Key rotation means generating a new key, re-encrypting data with the new key, and retiring the old key. Design your encryption layer to support multiple active keys so that rotation does not require downtime.
Use envelope encryption for large datasets. Instead of encrypting all data with a single master key, generate a unique data encryption key (DEK) for each record or batch of records. Encrypt the data with the DEK, then encrypt the DEK with your master key (KEK). Store the encrypted DEK alongside the encrypted data. This limits the exposure of any single key compromise and makes key rotation more efficient — you only need to re-encrypt the DEKs, not all the data.
Your secrets management infrastructure should be the foundation of your key management strategy. Keys are secrets, and they deserve the same level of protection — centralized storage, access logging, automatic rotation, and strict access controls.
Encryption at rest and in transit are complementary protections that together ensure your data is protected regardless of how it is accessed or intercepted. Neither is sufficient alone — encryption at rest does not protect data on the network, and encryption in transit does not protect data on disk. Implement both, manage your keys rigorously, and use authenticated encryption algorithms that protect integrity alongside confidentiality.