You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

纯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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 13:32:02