Why You Should Encrypt Sensitive Data at Rest

By Freddy ·

“Encryption at rest” gets treated as a checkbox: turn on disk encryption, tick the compliance form, move on. In practice, disk encryption solves a much narrower problem than most people assume, and the gap between what it protects and what a real breach exposes is where a lot of the damage happens. If you store passwords, tokens, personal records, or anything else you wouldn't want in a leaked database dump, it's worth understanding exactly what “at rest” covers and what it doesn't.

The three states data actually moves through

Data protection is usually described in three states, and each one needs a different defense:

Three states of data: in transit, at rest, and in useIn TransitTLS between clientand serverAt RestStored on diskor in a databaseIn UseHeld in memorywhile processingGreen = well-understood, widely enforced. Amber = frequently assumed, rarely verified.

“In transit” gets the most attention because TLS is easy to enforce and easy to verify: browsers flag a missing padlock, scanners flag an expired certificate. “At rest” is where teams get vague. Ticking “encryption at rest” on a compliance questionnaire usually just means the cloud provider's default disk or volume encryption is switched on, which is a real control, but a much weaker one than the phrase implies.

What disk-level encryption doesn't protect against

Full-disk or database-volume encryption (things like AWS EBS encryption, Azure Storage Service Encryption, or Transparent Data Encryption in Postgres and SQL Server) protects the physical medium. If someone steals the drive out of a rack, or if a cloud provider's storage backend is improperly decommissioned, the raw bytes are unreadable without the volume key.

What it doesn't protect against is almost every realistic breach scenario: a stolen database credential, a SQL injection vulnerability, an over-permissioned backup that got copied somewhere it shouldn't have, or an insider with legitimate query access. In every one of those cases, the database engine itself decrypts the volume transparently and hands back plaintext rows, because that's exactly what disk encryption is designed to do for any authenticated connection. The attacker doesn't need the disk key. They just need a working connection string.

Application-level encryption: encrypting before it ever reaches the disk

Application-level (sometimes called field-level) encryption moves the encryption step earlier: the application encrypts a specific value, using a key the database itself never has access to, before that value is ever written to a row. What lands in storage is ciphertext, and it stays ciphertext regardless of how someone gets access to the underlying data, whether that's a compromised credential, a leaked backup, or a misconfigured replica.

Disk encryption vs application-level encryption under a stolen credentialDisk encryption onlyStolencredentialDatabase(decrypts volume)Plaintext returnedattacker reads it directlyApplication-level encryptionStolencredentialDatabase(never held the key)Ciphertext onlyuseless without the key

The key difference is who holds the key. With disk encryption, the database process holds it (or fetches it automatically), so anything that can talk to the database can read plaintext. With application-level encryption, the key lives somewhere the database itself never touches, typically a secrets manager or a dedicated key management service, so a compromised database credential alone isn't enough to read the protected fields.

What this looks like in practice

Application-level encryption doesn't mean encrypting every column. That adds overhead and complexity for no benefit on data that isn't sensitive. It's worth reserving for specific fields: government ID numbers, payment details you're allowed to store, health information, private messages, API secrets belonging to your users. A few things matter for doing it correctly:

  • Use an authenticated mode. AES-256-GCM encrypts and verifies integrity in one step, so a modified ciphertext fails to decrypt instead of silently producing garbage. See AES-CBC vs AES-GCM for why GCM is the better default for new work.
  • Never reuse an IV with the same key. Each encryption operation needs a fresh, random initialization vector. Reusing one under GCM is a far more severe failure than under CBC, since it can let an attacker forge authenticated messages.
  • Keep the key out of the database entirely. A secrets manager or KMS with access logging and rotation support is worth the setup cost for anything handling real user data. Our guide to where AES keys should live covers the tradeoffs between environment variables, a secrets manager, and the options that look convenient but aren't safe.
  • Decide up front whether you need to query the field. Encrypted values generally can't be searched, filtered, or indexed the way plaintext can. If you need to look up a record by an encrypted field, you'll usually need a separate deterministic hash or a blind index alongside the encrypted value, not the encrypted value itself.

Symmetric or asymmetric?

For encrypting data your own system will later decrypt, a symmetric cipher like AES is almost always the right tool: it's fast, and both encrypting and decrypting use the same key, which is fine when your application controls both ends. Asymmetric encryption earns its keep when a third party needs to encrypt something only you can decrypt, without ever holding your private key. Our AES vs RSA comparison goes through that decision in more detail.

Try it before you build it

The Encrypt / Decrypt tool on this site is a fast way to see how AES-256-GCM behaves before wiring it into an application: encrypt a value, decrypt it back, then try changing a single character of the ciphertext and watch decryption fail outright instead of returning corrupted data. That's the authentication guarantee in action, and it's the same guarantee you want the field-level encryption in your own system to give you. Everything runs in your browser through the Web Crypto API, so nothing you test with is sent anywhere.

← Back to KeyForge