Documenting the pull request to add encryption to Active Record brought me memories about the origin of each feature:
- Support for unencrypted data: HEY was already used by staff and some beta users when we added encryption.
- Option to downcase: emails are not case-sensitive.
- Option to ignore case: labels are case-insensitive when matching them, but you want to show them with the right case.
- Support for previous encryption schemes: re-encrypting everything after a security firm reported a severe flaw in our deterministic encryption approach.
- Validate column size: addressing a security report via Hackerone where highly compressible contact names could bring the app down in Android devices. We realized this was a widespread vulnerability due to compression and fixed it accordingly.
- Filtering params: auditing our logs made us realize we now had a place to capture what's sensitive data in code, so it made sense to filter that out by default.
- Encrypting fixtures: keeping tests as realistic as possible without impacting how developers interacted with fixtures.
The whole idea of encryption contexts emerged from these two needs:
- Running blocks of code in a protected encryption context: supporting an auditable Rails console where you could interact with records normally without seeing the encrypted data, but with a protection where you couldn't override encrypted data.
- Running blocks of code without encryption: adding a debug option to HEY so that staff could see ciphertexts, to see at a glance what was encrypted in the early days (only usable by Basecamp staff).
The final design to support previous encryption schemes surged from combining encryption contexts with the initial support for unencrypted data.
In each step, we were not shy about changing things internally as we discovered new stuff.