Skip to slide
Chapter 12 · Secrets and Bring-Your-Own-Key
111 / 191

CHAPTER 12 · Secrets and Bring-Your-Own-Key · 3 / 10

Storing user secrets: encryption at rest

Never store a user secret in plaintext. Use authenticated symmetric encryption (AES-256-GCM is the standard choice):

  • Derive the encryption key from an operator secret held in the environment (e.g. hash a long random ENCRYPTION_SECRET into a 32-byte key). The encryption key lives in the environment, not in the database, so a database dump alone is useless to an attacker.
  • Encrypt with a fresh random IV per record. Store the ciphertext, the IV, and the authentication tag: the three outputs of GCM. Reusing an IV with GCM is catastrophic, so generate a new one every time you encrypt.
  • Authenticated encryption gives integrity, not just secrecy. A tampered ciphertext fails the auth-tag check on decryption rather than silently producing attacker-influenced plaintext.
  • Fail closed on decryption. If the auth tag doesn't verify (corruption, wrong key, tampering), return nothing and log; never return garbage that might be used as a credential.

Store each secret type in an appropriately-constrained table (e.g. a provider key per (user, provider); a separate table for a different token type so a check constraint reserved for providers isn't stretched).

← → arrow keys work too