rails / solid_cache

A database-backed ActiveSupport::Cache::Store
MIT License
890 stars 63 forks source link

Encrypts can’t decrypt binary column? #102

Closed emilkarl closed 3 months ago

emilkarl commented 1 year ago

Tried to use encryption on Rails 7.0.2 for my solid cache. Seems like it doesn’t work properly, it encrypts and stores the rows but it can’t be decrypted. It raises exception ActiveRecord::Encryption::Errors::Decrypt.

I changed my value column to be a text and that solves the issue but not sure that is the correct approach? Should it work with the binary column that comes with the default migration? In that case, am I missing some configuration that is not specified in the readme? 🤷‍♂️

Using postgresql.

All the best, Emil

Working migration

class CreateSolidCacheEntries < ActiveRecord::Migration[7.0]
  def change
    create_table :solid_cache_entries do |t|
      t.binary :key, null: false, limit: 1024
      t.text :value, null: false, limit: 512.megabytes
      t.datetime :created_at, null: false

      t.index :key, unique: true
    end
  end
end
formigarafa commented 1 year ago

That's probably right because the encryption will create a json in which one of the keys is rhe encrypted value. Of course binary can also hold that string but maybe, if that is supposed to work, there is some type conversion trickery missing or extra.

emilkarl commented 1 year ago

Sounds fine. Maybe this should be added to the docs. That if you want to use encrypts your value column have to be a text 🤷‍♂️

skatkov commented 1 year ago

Haven't taken a deep dive into encryption/decryption code. But it might be, that value needs to unescaped before decrypting.

PG::Connection.unescape_bytea(value)

djmb commented 10 months ago

The issue here is that Rails doesn't really support encrypting binary columns. I didn't realise this before because it just happens to work for Mysql (and SQLite). Not for PostgreSQL though.

I've raised https://github.com/rails/rails/pull/50920 to add proper support. Hopefully that will resolve it. In the meantime I'll update the docs to highlight this.

Another note is that there's a potential space saving here. ActiveRecord Encryption serializes messages to JSON with a Base64 encrypted payload which means they use about 30% more space than a binary encoding. Once binary data is properly supported, we could use a MessagePack based serializer for binary columns instead.