Encrypting Credential Records at Rest

A WebAuthn credential table holds no secrets — the public key is public and the credential identifier is disclosed to the client on every ceremony. What it does hold is a durable link between a person and the devices they use, and that is what encryption at rest should be protecting. This page covers which columns are worth encrypting, why the lookup key must not be among them, and how the two common encryption strategies address different threats. It sits under Handling Public Key Storage and Rotation.


Sensitivity Reference

Field Secret? Personal data? Encrypt at column level?
credential id no weakly — it is a per-account identifier no — it is the index
public key no no no benefit
algorithm no no no
user handle no yes, by linkage yes, or tokenise
device label / AAGUID no yes, by inference yes
enterprise serial no yes, strongly yes, always

The pattern is that everything used to verify is public, and everything used to identify deserves protection.

What is actually sensitive here No secret is stored, but the linkage between people and devices is personal data. The linkage is the asset, not the key material public key public by definition — encryption adds nothing credential id disclosed to the client on every ceremony; not secret user handle opaque, but it links a device to an account AAGUID and device labels reveal what hardware a person uses enterprise serial a durable hardware identifier — treat as sensitive

Root Cause Analysis

1. Encrypting the public key for appearances. It is public. Encrypting it satisfies a checkbox, adds a decryption to every verification, and protects nothing.

2. Encrypting the credential id. This is the genuinely harmful mistake: the column is the unique index that makes authentication a single read, and an encrypted value cannot be indexed for equality unless the encryption is deterministic — which reintroduces the correlation you were trying to remove.

3. Relying on full-disk encryption alone. It protects a stolen disk or an offline backup. It does nothing about an exported dump taken from a running database, which is the shape most real breaches take.

4. Storing an enterprise device serial like any other column. It is a globally unique, durable hardware identifier — the one field in this table that genuinely warrants the strongest handling you have.

Encrypting selectively Column-level encryption on the identifying fields costs far less than encrypting a table you must also index. Encrypt what identifies, not what verifies credential id indexed — leave in the clear public key not secret — no benefit user handle encrypt or tokenise device labels encrypt at column level Encrypting the credential id would destroy the unique index that makes authentication a single read.

Step-by-Step Resolution

Step 1 — classify the columns before encrypting anything

Verification material is public; identifying material is personal. The classification decides everything else.

Step 2 — leave the lookup key indexable

The credential identifier stays in the clear, stored as bytes, with its unique index intact.

Step 3 — encrypt or tokenise the user handle

If your platform supports envelope encryption at the column level, use it. If not, a tokenisation table keyed on a random surrogate achieves the same separation.

Step 4 — encrypt device-identifying metadata

Labels the user chose, resolved model names and any enterprise serial. These are the fields that turn a dump into a device inventory.

Step 5 — keep keys out of the same blast radius

A key stored beside the data it protects is decoration. Use your platform’s key management service, rotate on a schedule, and make sure a database export cannot include the key material.

Step 6 — delete on revocation

Encryption is not a substitute for deletion. When a credential is purged on your retention schedule, the identifying fields must go with it.

Two threat models, two answers Full-disk encryption answers a stolen-disk threat; column encryption answers a leaked-dump threat. They mitigate different things and are not alternatives storage-level protects a stolen disk or backup transparent to queries no key management in the application useless against a dump from a live database column-level protects an exported dump requires key management breaks indexing on encrypted columns the answer for identifying fields Most deployments want both, applied to different columns for different reasons.

Verification and Testing

Export a database dump in a test environment and read it. Anything legible that identifies a person or a device is a finding, and this exercise takes minutes while producing a more honest answer than any configuration review.

Assert that authentication still performs a single indexed read after encryption is applied. A query plan that has degraded to a scan is the signature of an encrypted lookup column, and it will not be obvious from functional tests.

Test key rotation end to end: rotate, then read an old row. Envelope encryption makes this cheap, and a rotation that has never been exercised is a rotation that will fail the first time it is needed.


Pitfalls

1. Deterministic encryption on an identifying column. Preserves equality, and therefore preserves exactly the correlation you were removing.

2. Treating encryption as a retention policy. Encrypted personal data is still personal data.

3. Encrypting the whole row. Costs a decryption on every verification and prevents indexing.


Frequently Asked Questions

Is a leaked credential table an authentication incident?

No. Nothing in it can be used to authenticate: the public key verifies signatures but cannot produce them, and the credential identifier is already known to the client. It is a privacy incident, because it discloses who has an account and what devices they use, and it should be handled under that heading rather than as a credential compromise.

Should the signature counter be encrypted?

There is no need. It is an integer with no identifying value on its own, and it is written on every successful assertion, so encrypting it adds a decrypt-modify-encrypt cycle to the hot path for no benefit.

Does encryption help with a compromised application server?

Not much. An application that can decrypt in order to function can be made to decrypt by an attacker who controls it. Column encryption addresses exports and backups; it is not a defence against code execution in the service that holds the keys.

What about the exclude list — does it leak anything from storage?

It discloses credential identifiers to the authenticated account holder, which is intended. The concern with storage is different: a dump that pairs identifiers with user handles and device labels is what allows a person’s devices to be enumerated, which is why those two columns are the ones to protect.

How does this interact with data-subject deletion requests?

Deleting the account must delete the credential rows, not merely mark them revoked, once your retention window has passed. A soft-deleted row that still carries a user handle and a device label is exactly the kind of residue such a request is meant to remove, and encryption does not exempt it.

Is tokenisation better than encryption for the user handle?

It is often simpler. A random surrogate stored in the credential table, with the mapping held in a separate store with its own access controls, achieves the separation without key management inside the credential path. The trade-off is an extra lookup when you genuinely need the handle, which is only during a usernameless ceremony.


Does any of this change for a multi-tenant deployment?

The classification does not, but the blast radius does. In a shared table the linkage disclosed by a dump spans every tenant at once, which raises the value of encrypting the identifying columns and of keeping key material outside the database entirely. Per-tenant key separation is worth considering where the tenants are genuinely distinct organisations, because it converts a single dump into a set of separately protected datasets — at the cost of a key-management story that has to work at tenant granularity.

Whatever separation you adopt, write down which threat each layer addresses. An encryption scheme nobody can explain in one sentence tends to survive reviews without ever being checked against the threat it was supposed to mitigate, and it is usually the identifying columns that turn out to be the ones left in the clear.

Related