What "Encrypted at Rest" Protects Against—and What It Doesn’t
This guide is for non-engineering buyers and product owners who keep seeing "encrypted at rest" in proposals, cloud dashboards, and compliance checklists. You’ll learn what it actually protects in a real system, where it sits in the request flow, and when it meaningfully reduces risk versus when it is mostly table stakes.
TL;DR — "Encrypted at rest" means stored data is unreadable without a key if someone gets the raw storage: a stolen disk, a bad backup copy, or low-level access to storage media. It does not protect you from an attacker who is already inside your app, logged into your database, or using a server that has the decryption keys loaded; for most teams, the key takeaway is to treat it as a baseline storage control, not as your main defense against breaches. Reading time: ~7 min
What it is and where it sits
"Encrypted at rest" means data is encrypted (scrambled so it is unreadable without a key) while stored on disk, SSD, object storage, snapshots, or backups. The important phrase is at rest: the protection applies when the data is sitting in storage, not when your app is actively reading and using it.
In a typical web system, your customer sends a request to your app over TLS (the web lock icon; encryption in transit). Your app then reads or writes data to a database, file store, or backup system. Encryption at rest usually lives inside the storage layer or just above it:
- database storage volume
- object storage bucket
- managed database snapshots/backups
- block disks attached to servers
- sometimes individual database columns or files
What it replaces depends on the level:
- Disk/storage encryption replaces plain bytes on disk with encrypted bytes.
- Database-level encryption replaces plain database files with encrypted files.
- Application-level encryption replaces plain field values with encrypted values before they ever reach the database.
Those are very different controls.
Here is the usual request/data flow:
View as text
[User Browser] ---- 1. HTTPS request ----> [Web App] [Web App] ---- 2. SQL query ----> [Database Engine] [Database Engine] ---- 3. read/write pages ----> [Encrypted Disk] [Database Engine] <---- 4. decrypted data in memory ---- [Encrypted Disk] [Web App] <---- 5. rows returned ---- [Database Engine]
The key architectural point: the database engine or storage service usually decrypts data automatically when an authorized system asks for it. So if your app can read the record normally, encryption at rest is not blocking that read.
What it protects against
It is strongest against threats like:
- a stolen physical drive from a data center
- someone copying raw storage blocks or database files
- a leaked snapshot or backup file
- improper disposal of old disks
- some classes of insider access at the infrastructure layer
What it does not protect against
It is weak or irrelevant against:
- SQL injection (an attacker tricks your app into reading the database)
- stolen app credentials
- a compromised server that already has access to the key
- a malicious admin reading data through the normal database interface
- data shown in logs, exports, screenshots, or downloaded CSVs
- data sent over the network without TLS
That is why vendors love to advertise it: it is real and useful, but it is often only one layer of a larger security design.
How it actually works
At a practical level, encryption at rest uses a key (a secret value used to encrypt/decrypt data). The storage system writes encrypted bytes to disk. When an authorized database or storage service needs the data, it gets the key, decrypts the bytes, and returns normal readable data to the app.
A common setup looks like this:
- Your cloud provider or database service creates or uses an encryption key.
- Data is written to storage in encrypted form.
- The key is stored in a key management service (a service that stores and controls encryption keys) or managed internally by the provider.
- When the database starts or reads data, it asks for permission to use the key.
- The database decrypts the needed pages in memory (RAM; temporary working memory), not on disk.
- Your app receives normal plaintext values because it is an authorized caller.
One realistic example: customer records in Postgres
Imagine your app stores customer names, emails, and invoices in Postgres on a managed cloud database.
Step 1: Customer submits a form
A user updates their billing address in your app over HTTPS.
Step 2: App writes to the database
Your app sends an UPDATE query to Postgres.
Step 3: Postgres writes encrypted pages to storage
Postgres itself may not be doing the disk encryption directly; the managed database platform or encrypted volume often handles that. On the underlying disk, the database files are unreadable without the key.
If someone steals the raw disk image, they see encrypted bytes, not rows and tables.
Step 4: Later, your app reads the record
A support agent opens the customer profile. The app runs a SELECT query. Postgres reads the encrypted storage pages, decrypts them using the available key, and returns the customer record to the app.
Step 5: The support agent sees readable data
Because the app and database are authorized, the data appears normally in the UI.
Now compare three attack scenarios:
- Stolen snapshot file: encryption at rest helps a lot. The snapshot is unreadable without the key.
- Attacker got read-only SQL access: encryption at rest does not help much. The database returns decrypted rows.
- Attacker exploited your app and downloaded customer exports: encryption at rest does nothing for that event. The app already had legitimate access.
That is the core mental model: encryption at rest protects the stored media, not every path by which data can be viewed.
When to use it (and when not to)
For most production systems, you should treat encryption at rest as the default baseline. The real decision is usually what level you need: provider-managed storage encryption, customer-managed keys, or application-level encryption for especially sensitive fields.
| Scenario | Recommendation |
|---|---|
| Standard SaaS app storing customer accounts, orders, files | Use provider or managed-service encryption at rest everywhere it is offered. |
| You store regulated data (health, finance, government, high-value PII) | Use encryption at rest plus tighter key management, access controls, audit logs, and likely field-level encryption for the most sensitive values. |
| You need protection from stolen backups or disks | Encryption at rest is directly relevant and worth doing. |
| You are worried about SQL injection or compromised app credentials | Encryption at rest is not the main fix; prioritize input validation, least-privilege database access, MFA, secret rotation, and monitoring. |
| You need your cloud provider admins to be unable to read certain fields easily | Consider application-level encryption where your app controls the keys, not just disk encryption. |
| Internal prototype with fake data and no external users | You probably do not need custom key architecture yet; basic managed encryption is enough. |
| Small app on a managed platform where encryption is already on by default | You probably do not need a separate project for this; verify it in the dashboard and move on to higher-risk controls. |
You probably don't need more than the default if...
- your provider already encrypts managed databases, disks, and object storage by default
- you do not have a compliance requirement for customer-managed keys
- your bigger risks are weak passwords, over-broad admin access, or missing backups
- your team is small and cannot safely operate a custom key system
You probably need more than the default if...
- you handle highly sensitive fields like SSNs, card data, or health records
- you need to revoke key access independently of the storage provider
- you need stronger separation between infrastructure admins and data access
- your contracts or auditors ask who controls the keys and how rotation works
Trade-offs
Encryption at rest is good security hygiene, but every benefit has a cost.
| Benefit | What it costs |
|---|---|
| Protects raw disks, snapshots, and backups if copied or stolen | Usually little performance cost, but some operational complexity around keys and recovery |
| Helps with compliance questionnaires and customer trust | Can create a false sense of safety if teams assume it stops app-level breaches |
| Easy to enable on many managed services | Harder to change later if you need customer-managed keys or app-level encryption |
| Customer-managed keys give you more control | More setup, more failure modes, and possible outages if keys are disabled or permissions break |
| Application-level encryption protects especially sensitive fields better | Search, sorting, indexing, analytics, and debugging become harder |
| Key rotation reduces long-term exposure | Rotation planning, testing, and re-encryption jobs can take time and money |
Two honest points that matter in agency projects:
- The cheapest version is often enough. If your provider offers managed encryption by default, take it.
- The strongest version changes product behavior. Once you encrypt fields in the application, you may lose easy filtering, reporting, and support workflows.
In practice
Below are two examples you can adapt today. Start in your provider dashboard if possible: look for your database, disk, bucket, or backup settings and check for an "Encryption" or "Security" section. In many providers, this is under paths like Database → Settings → Security, Storage → Bucket → Properties, or Compute → Disk/Volume → Edit.
Example 1: Verify Postgres SSL and see that app-level reads still return plaintext
This example shows the practical limit: even with encrypted storage underneath, an authorized SQL session still reads normal values.
-- Connect using your database client, then run:
SHOW ssl;
SELECT id, email, billing_address
FROM customers
WHERE id = 42;
What it does: SHOW ssl; confirms whether the database connection is using TLS in transit. The SELECT shows that authorized reads return plaintext values to the client, which is why encryption at rest does not stop misuse through valid database access. Gotcha: TLS on the connection and encryption at rest are separate controls; one does not imply the other.
Example 2: Encrypt a sensitive field in the application before storing it
If you need protection beyond disk encryption, encrypt the specific field before it reaches the database. Here is a simple Node.js example using AES-GCM (a common authenticated encryption mode).
⚠️ If you lose the encryption key used below, you can permanently lose access to the data. Store keys in your provider's secret manager or key management service, not in source code or a
.envfile committed to Git.
const crypto = require('crypto');
const key = Buffer.from(process.env.FIELD_ENCRYPTION_KEY, 'base64'); // 32 bytes
function encryptString(plaintext) {
const iv = crypto.randomBytes(12);
const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
const encrypted = Buffer.concat([
cipher.update(plaintext, 'utf8'),
cipher.final()
]);
const tag = cipher.getAuthTag();
return Buffer.concat([iv, tag, encrypted]).toString('base64');
}
function decryptString(payload) {
const data = Buffer.from(payload, 'base64');
const iv = data.subarray(0, 12);
const tag = data.subarray(12, 28);
const encrypted = data.subarray(28);
const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv);
decipher.setAuthTag(tag);
return decipher.update(encrypted, null, 'utf8') + decipher.final('utf8');
}
const encryptedSsn = encryptString('123-45-6789');
console.log(encryptedSsn);
console.log(decryptString(encryptedSsn));
What it does: this encrypts a sensitive value before you insert it into the database, so a raw database dump does not contain the original value. Gotcha: encrypted fields are much harder to search or filter; exact-match lookups usually require a separate design, not a quick patch.
Example 3: Check Linux block-device encryption on a self-managed server
If you run your own VM or dedicated server, this is the CLI way to verify whether a disk uses LUKS (a common Linux disk encryption format).
lsblk -f
sudo cryptsetup status cryptroot
What it does: lsblk -f lists filesystems and mapped devices; cryptsetup status shows whether the named encrypted volume is active. Gotcha: this only applies if you manage the server yourself; on managed databases and managed object storage, you usually verify encryption in the provider dashboard or service settings instead.
Further reading
- PostgreSQL Documentation: "Encryption Options"
- AWS Key Management Service Developer Guide
- Google Cloud: Cloud KMS documentation
- NIST SP 800-111: Guide to Storage Encryption Technologies for End User Devices
- OWASP Cryptographic Storage Cheat Sheet
This article was written by an AI system and published pending human review. Verify anything you intend to act on.
Have a project in mind?
Get an instant AI price estimate for it, or talk directly to our team.
One email a month on what we learn building with AI