纯Ruby环境解密Rails Active Record加密字段失败求助
Rails 7 Active Record Encryption 跨应用解密失败排查与修复
问题背景
现有一个Rails 7应用,orders表中部分字段通过Active Record Encryption加密。尝试在Rails外的Ruby Lambda函数中解密这些字段,已确认使用相同加密密钥,但解密失败,报错ActiveRecord::Encryption::Errors::Decryption及OpenSSL::Cipher::CipherError。
代码与报错信息
代码文件
lambada_function.rb
require 'active_support/all' require 'active_record' require_relative 'application' require_relative './models/order' require 'pry' last_order = Order.last ActiveRecord::Encryption::Encryptor.new.decrypt(last_order.user_surname)
application.rb
# frozen_string_literal: true require 'active_record' require 'tzinfo' class Application env_file = File.join('./config_env.yml') YAML.safe_load(File.open(env_file), aliases: true).each do |key, value| ENV[key.to_s] = value end db_configuration_file_path = './db/database.yml' db_configuration = YAML.safe_load(File.read(db_configuration_file_path), aliases: true) ActiveRecord::Base.establish_connection(db_configuration['production']) tz = TZInfo::Timezone.get('Asia/Tokyo') Time.zone = tz ActiveRecord.default_timezone = :local ActiveRecord::Encryption.configure( primary_key: ENV['PRIMARY_KEY'], deterministic_key: ENV['DETERMINISTIC_KEY'], key_derivation_salt: ENV['KEY_DERIVATION_SALT'], support_unencrypted_data: true ) end
order.rb
class Order < ActiveRecord::Base # encrypt user information encrypts :user_name, deterministic: true end
报错信息
/Users/vebuinuser/Documents/Belc/ruby_lambada/ruby/3.2.0/gems/activerecord-7.0.4/lib/active_record/encryption/encryptor.rb:58:in `rescue in decrypt': ActiveRecord::Encryption::Errors::Decryption (ActiveRecord::Encryption::Errors::Decryption) from /Users/vebuinuser/Documents/Belc/ruby_lambada/ruby/3.2.0/gems/activerecord-7.0.4/lib/active_record/encryption/encryptor.rb:52:in `decrypt' from lambda_function.rb:10:in `<main>' /Users/vebuinuser/Documents/Belc/ruby_lambada/ruby/3.2.0/gems/activerecord-7.0.4/lib/active_record/encryption/cipher/aes256_gcm.rb:80:in `rescue in decrypt': ActiveRecord::Encryption::Errors::Decryption (ActiveRecord::Encryption::Errors::Decryption) from /Users/vebuinuser/Documents/Belc/ruby_lambada/ruby/3.2.0/gems/activerecord-7.0.4/lib/active_record/encryption/cipher/aes256_gcm.rb:56:in `decrypt' from /Users/vebuinuser/Documents/Belc/ruby_lambada/ruby/3.2.0/gems/activerecord-7.0.4/lib/active_record/encryption/cipher.rb:42:in `block in try_to_decrypt_with_each' from /Users/vebuinuser/Documents/Belc/ruby_lambada/ruby/3.2.0/gems/activerecord-7.0.4/lib/active_record/encryption/cipher.rb:41:in `each' from /Users/vebuinuser/Documents/Belc/ruby_lambada/ruby/3.2.0/gems/activerecord-7.0.4/lib/active_record/encryption/cipher.rb:41:in `with_index' from /Users/vebuinuser/Documents/Belc/ruby_lambada/ruby/3.2.0/gems/activerecord-7.0.4/lib/active_record/encryption/cipher.rb:41:in `try_to_decrypt_with_each' from /Users/vebuinuser/Documents/Belc/ruby_lambada/ruby/3.2.0/gems/activerecord-7.0.4/lib/active_record/encryption/cipher.rb:26:in `decrypt' from /Users/vebuinuser/Documents/Belc/ruby_lambada/ruby/3.2.0/gems/activerecord-7.0.4/lib/active_record/encryption/encryptor.rb:56:in `decrypt' from lambda_function.rb:10:in `<main>' /Users/vebuinuser/Documents/Belc/ruby_lambada/ruby/3.2.0/gems/activerecord-7.0.4/lib/active_record/encryption/cipher/aes256_gcm.rb:76:in `final': OpenSSL::Cipher::CipherError from /Users/vebuinuser/Documents/Belc/ruby_lambada/ruby/3.2.0/gems/activerecord-7.0.4/lib/active_record/encryption/cipher/aes256_gcm.rb:76:in `decrypt' from /Users/vebuinuser/Documents/Belc/ruby_lambada/ruby/3.2.0/gems/activerecord-7.0.4/lib/active_record/encryption/cipher.rb:42:in `block in try_to_decrypt_with_each' from /Users/vebuinuser/Documents/Belc/ruby_lambada/ruby/3.2.0/gems/activerecord-7.0.4/lib/active_record/encryption/cipher.rb:41:in `each' from /Users/vebuinuser/Documents/Belc/ruby_lambada/ruby/3.2.0/gems/activerecord-7.0.4/lib/active_record/encryption/cipher.rb:41:in `with_index' from /Users/vebuinuser/Documents/Belc/ruby_lambada/ruby/3.2.0/gems/activerecord-7.0.4/lib/active_record/encryption/cipher.rb:41:in `try_to_decrypt_with_each' from /Users/vebuinuser/Documents/Belc/ruby_lambada/ruby/3.2.0/gems/activerecord-7.0.4/lib/active_record/encryption/cipher.rb:26:in `decrypt' from /Users/vebuinuser/Documents/Belc/ruby_lambada/ruby/3.2.0/gems/activerecord-7.0.4/lib/active_record/encryption/encryptor.rb:56:in `decrypt' from lambda_function.rb:10:in `<main>'
问题排查与修复步骤
1. 加密配置未生效
Application类仅定义了配置逻辑,但未被实例化,导致ActiveRecord::Encryption.configure从未执行。修改lambda_function.rb,初始化Application:
require 'active_support/all' require 'active_record' require_relative 'application' require_relative './models/order' require 'pry' # 初始化Application,触发加密配置 Application.new last_order = Order.last # 模型已定义encrypts,直接访问字段即可自动解密 puts last_order.user_name # 注意:order.rb中仅加密了user_name,不是user_surname
2. 错误的字段操作
在order.rb中仅配置了encrypts :user_name,但代码中尝试解密user_surname,该字段可能未加密,或配置遗漏。如果user_surname确实需要加密,需在模型中添加:
class Order < ActiveRecord::Base encrypts :user_name, deterministic: true encrypts :user_surname # 或根据需求添加deterministic: true end
3. 手动解密的正确方式(若需手动处理)
如果必须手动调用Encryptor,需根据字段的加密类型(是否deterministic)使用对应的密钥上下文:
# 对于deterministic加密的字段(如user_name) deterministic_encryptor = ActiveRecord::Encryption::Encryptor.new( key_provider: ActiveRecord::Encryption.key_provider.deterministic_key_provider ) decrypted_value = deterministic_encryptor.decrypt(last_order.user_name) # 对于非deterministic加密的字段 regular_encryptor = ActiveRecord::Encryption::Encryptor.new decrypted_value = regular_encryptor.decrypt(last_order.user_surname)
4. 密钥验证
确保config_env.yml中的密钥与Rails应用完全一致:
- Rails中对应的环境变量通常为
ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY、ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY、ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT,需确认config_env.yml中的键名是否匹配,或在application.rb中正确映射:
ActiveRecord::Encryption.configure( primary_key: ENV['ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY'], deterministic_key: ENV['ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY'], key_derivation_salt: ENV['ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT'], support_unencrypted_data: true )
5. 依赖版本一致性
确保Lambda函数中使用的activerecord版本与Rails应用完全一致(当前为7.0.4),避免版本差异导致的加密算法实现不同。
内容的提问来源于stack exchange,提问作者Aniruddha Mirajkar
相关产品推荐
相关产品推荐

