Encryption in Raft
User key management
Raft takes advantage of a webauthn extension called PRF that allow the web application to obtain a secure secret when the user logs in. Raft uses this secret to generate a public/private key pair that is used to unlock the user’s personal vault.
The personal vault securely stores the encryption keys for each workspace that the user has access to. The vault is unlocked at the start of every web request, and then locked again at the end of the each web request. At no time does the database server have access to the keys stored in the vault.
Most of the time, encryption allows you to solve the problem of confidentiality by creating a new problem of how to manage keys. The Webauthn PRF extension allows for automatic key management, with very strong high-entropy keys, that is invisible to the user.
Workspace keys
Every workspace has its own encryption key. Nearly all content, and some metadata, is encrypted using this key while stored in the database. Workspace content is only readable by the web application while a single web request is being processed or a single background job is being processed.
The objective with database encryption in Raft is to limit the potential for disclosure of sensitive information stored in the database, either because of an attack on the servers, negligence by the provider, a nefarious worker, or a court-ordered subpoena.
Per-user encryption at rest
How does this work? TL;DR edition:
When the user makes a request to the web application, the user’s personal vault is loaded, the workspace key is read from the vault, the database records are decrypted, and the values are returned to the user’s web browser.
Encryption and decryption takes place in the web application, not the browser or the database. These scheme could be called “per-user encryption at rest” because each user has their own vault and the data stored in the database (“at rest”) is encrypted so only the user can read it (and the web application while the user’s session is active).
There are six methods of database encryption:
-
Row encryption: individual database rows are encrypted using a random IV and the workspace key (IV is a random, unique seed necessary for block cipher encryption). Not all columns are encrypted, but most sensitive content is. Each row may be encrypted with a different key.
-
Searchable encryption: the searchable content is tokenized (separated into discrete words), shuffled in random order, and then each token is deterministically encrypted. To do this, the IV chosen is not random but derived from the digest of the token (and other key material). So, the token “cat” will always produce the same ciphertext for a given workspace. Searching these deterministically encrypted tokens is extremely fast, allowing for a user experience that feels like normal full text search (albeit without stemming or trigram support). Deterministic encryption like this is vulnerable to frequency analysis and chosen plaintext attacks should the database be entirely compromised. See search for a longer discussion.
-
S3 storage object encryption: attachments and files are stored in an object storage service compatible with the S3 protocol. Like the database, these objects are encrypted before being sent to the S3 service and decrypted when being read from the S3 service using a block cipher, random IV, and the workspace key.
-
App encryption: Some columns are not encrypted to the workspace key, but instead to a global, shared application key. The application key is primarily used for encrypting short-lived background jobs (e.g. generating a zip file for export).
-
Session encryption: All data in a user’s session, including their unlocked vault, is encrypted using a special session key. The session key is stored in the client’s session cookie. When a page load happens, the browser sends the cookie to the server, the server extracts the session id and key from the cookie, then loads and decrypts the session from the database, and finally erases the session key. This means that a user’s sensitive vault is available to the server only during page request, and not a moment after.
-
Link encryption: Users may create invites to join a workspace or links that grant access to a particular resource (such as a document or folder). These links contain the workspace key. To guard against key disclosure, the workspace key in the link is encrypted with the app key, and then encrypted again with another key that is deleted from the database on the day the link expires.
What is not encrypted at rest? The user’s login name and workspace names are not encrypted. Some indexed ordinal fields are not encrypted, such as dates used for calendar queries.
Workflow
Log in:
- User logs in
- The webauthn authenticator (e.g. security key) is given a seed value unique to the authenticator’s id.
- The authenticator responds with a deterministic digest of the seed, the “prf secret”.
- Vault is unlocked
- This “prf secret” & salt are used to generate a public/private key pair.
- The private key is used to unlock the user’s personal vault.
- Session is encrypted
- The web application generates a random session id and session secret.
- A new session record is created in the database, encrypted using the random session secret.
- The session record stores the newly unlocked personal vault.
- The web application responds to the browser with the new session cookie, containing only the session id and session secret.
- The “prf secret”, private key, personal vault, and session secret are forgotten by the web app.
On every web request:
- Load the session
- The browser sends the cookie to the server (which includes a session id & session secret)
- The session record is fetched from the database using the session id and decrypted using the session secret
- Load the vault
- The personal vault is loaded from the decrypted session record.
- Decrypt database records
- The workspace key is loaded from the personal vault
- Workspace records are loaded from the database and decrypted by the app using the workspace key
- Send response
- The web app sends it’s HTML response back to the browser.
- The session, session secret, personal vault, and workspace keys are forgotten by the web app at the end of the request
Log out:
- All session records associated with the user are destroyed.