Lindsay Holmwood
June 23, 2022
Searching your encrypted data with ActiveRecord Encryption + ActiveStash
Encrypt your data with ActiveRecord Encryption. Perform fully encrypted searches with ActiveStash. It's really that easy.

Rails 7 introduced ActiveRecord Encryption to Rails. This brings powerful application-level encryption to ActiveRecord models, and helps developers to seamlessly encrypt and decrypt specific database fields.
ActiveRecord Encryption follows the footsteps of application-level encryption plugins for ActiveRecord like Lockbox, attr_encrypted, CryptKeeper , and Strongbox.
However, there is one huge drawback to using application-level encryption:
When you encrypt your data, you lose the ability to search.
For most developers, losing the ability to search their data isn’t worth the security gain.
ActiveStash + CipherStash eliminates this tradeoff.
With ActiveStash, you can encrypt your data inside Rails, but still search it.
Most importantly, the index that ActiveStash searches is fully encrypted, due to CipherStash’s groundbreaking searchable encryption technology.
CipherStash never sees your keys or plaintext when indexing or searching your data.
ActiveStash helps you do range queries, ordering, and full text search on encrypted data.
When your records are protected by ActiveRecord Encryption and you try and do a range query, you hit a roadblock instantly:
> User.where("dob > ?", 20.years.ago) => []
ActiveStash gives you range queries back:
> User.query { |q| q.dob > 50.years.ago } => [#<User id: 19, first_name: "Grace", ...>, #<User id: 20, first_name: "Ada", ... >]
When your records are protected by ActiveRecord Encryption and you try to order your results, yet another roadblock:
> User.order(:name) => [#<User id: 905456733, name: "Margaret Hamilton">, #<User id: 258552901, name: "Anita Borg">, #<User id: 370882803, name: "Grace Hopper">, #<User id: 134100488, name: "Radia Perlman">, #<User id: 225478506, name: "Ada Lovelace">, #<User id: 391913150, name: "Frances Allen">]
On first glance, the records don't appear to be ordered. But if you look closer, the data is sorted — but by the underlying ciphertexts, instead of the actual plaintext data.
sqlite> SELECT name FROM users ORDER BY name; name {"p":"Q0RgizFz7xhF5CRC8GhxB0E=","h":{"iv":"6BGlZdALhMgRh0cl","at":"Dk9A2veUedsFPwLbxUm3Iw=="}} {"p":"bBko5ZVXQFk3lg==","h":{"iv":"gHrORcZV0jfHUqTU","at":"VyS3Gh/yOGqQw+erC5QvzQ=="}} {"p":"cOs/2cNA+YWe0p70","h":{"iv":"irn45NHdZ7qvI4Un","at":"T0EEKMMGGHram9p4Qu2Fsw=="}} {"p":"h8UOa4MZwmlDVnYtQQ==","h":{"iv":"IVG6+IAjxV801XBD","at":"htxQMmQNi+rd5PzlAXa28Q=="}} {"p":"kCEc2m+ZSS/lsb2c","h":{"iv":"xiCC1UUF+VXHt6PC","at":"Zt+gOLffNMHMQvY9Xe7Zmg=="}} {"p":"kyjwkJsciDqs9h8pNA==","h":{"iv":"eiDWZGtUL0bcLlzF","at":"JndrnAn/QLEDcqiAhoRYjA=="}}
ActiveStash gives you ordering back:
> User.query.order(:name) => [#<User id: 225478506, name: "Ada Lovelace">, #<User id: 258552901, name: "Anita Borg"> #<User id: 391913150, name: "Frances Allen"> #<User id: 370882803, name: "Grace Hopper">, #<User id: 905456733, name: "Margaret Hamilton">, #<User id: 134100488, name: "Radia Perlman">]
When your records are protected by ActiveRecord Encryption and you try to do a full text search, you hit another dead end:
> User.where("name LIKE '%ace%'") => []
ActiveStash gives you encrypted full text search, with comparable performance to what you get from your plain text full text search that your database has right now:
> User.query { |q| q.name =~ "ace" } => [#<User id: 225478506, name: "Ada Lovelace">, #<User id: 370882803, name: "Grace Hopper">]
Best yet, ActiveStash works with any database that ActiveRecord supports: PostgreSQL, MySQL and its ilk, SQL Server, SQLite, and Oracle.
ActiveStash keeps your encrypted data searchable, regardless of the underlying database.
Add ActiveStash to your app in under 5 minutes.
- Add ActiveStash to your
Gemfile
:
gem "active_stash"
- Install the new dependencies:
$ bundle install
- Create a CipherStash account (which will provision you a workspace) and then login:
$ rake active_stash:signup
Note the workspace ID you are issued at the end.
Note: If you are using zsh
you may need to escape the brackets
$ rake active_stash:login\['WorkspaceId'\]
- Any model you use with
ActiveStash::Search
needs to have astash_id
column, to link search results back to database records.
For example, to add a stash_id
column to the database table for the User
model, add the below migration:
$ rails generate migration AddStashIdToUser stash_id:string:index $ rails db:migrate
- Add the
ActiveStash::Search
mixin to your User model, and declare what fields are searchable:
# app/models/user.rb class User < ApplicationRecord include ActiveStash::Search # Previously added application-level encryption encrypts :name, :email encrypts :dob, type: :date # Fields that will be indexed into CipherStash stash_index :name, :email, :dob end
- Reindex your existing data with ActiveStash
$ rails active_stash:reindexall
- Query a user record:
> User.where(name: "Grace Hopper") => [] # No records, because the database isn't searchable. > User.query(email: "grace@example.com") => [#<User id: 370882803, name: "Grace Hopper", ...>]
Next steps
ActiveStash is free to use for indexing up to 10,000 record per month, and returning 100,000 records in searches per month.
- Check out the code on GitHub. You can even sign up from the command line.
- Read the ActiveStash documentation to learn about the capabilities ActiveStash gives you.
- Watch the demo video to see ActiveStash in action.
- Check out our guide for deploying to production for when you are ready to take your data security to the next level.
About the Author
Latest Posts
View All Articles

Howto
Searching your encrypted data with ActiveRecord Encryption + ActiveStash
Encrypt your data with ActiveRecord Encryption. Perform fully encrypted searches with ActiveStash. It's really that easy.
Lindsay Holmwood
June 23, 2022

Howto
Convert the User model in your Prisma/Next.js app to CipherStash
In this article we cover how to create a secure, searchable data vault for your users using TypeScript and Next.js, and safely migrate your existing data.
Dan Draper
April 12, 2022

Engineering
Linting your GitHub Actions
Your infrastructure-as-code is still code, and all that YAML needs to be checked for correctness. So does ours, and we did something about it.
Matt Palmer
November 25, 2021