商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > Rails实现字段加密存储

Rails实现字段加密存储

  发布于2026-06-29 阅读(0)

扫一扫,手机访问

在 Rails 应用中处理敏感字段,比如用户手机号、地址、姓名这些信息,直接以明文形式存进数据库多少让人有些不放心。一个常见的做法是:存储前,先把数据加密再写入;读取后,再用对应的密钥解密还原。

这其实来自一个非常实用的思路:数据在落盘那一刻就应该是密文,业务层拿到的则是解密后的原文,整个过程对上层代码完全透明。

那么,在 Rails 框架下怎么把这个流程做得既安全又干净?

核心工具:ActiveSupport::MessageEncryptor

这个类是 Rails 基于 OpenSSL 封装出来的一个加密解密工具箱,用法很直接。你只需要先生成一个密钥,然后实例化一个加密器,接下来就能对任意对象进行加密并签名验证了。举个例子:

salt = SecureRandom.random_bytes(64)
key  = ActiveSupport::KeyGenerator.new('password').generate_key(salt) # => "x89xE0x156xAC..."
crypt = ActiveSupport::MessageEncryptor.new(key)            # => #
encrypted_data = crypt.encrypt_and_sign('my secret data')       # => "NlFBTTMwOUV5UlA1QlNEN2xkY2d6eThYWWh..."
crypt.decrypt_and_verify(encrypted_data)                # => "my secret data"

这套组合拳打下来,加密后的数据带着签名,无论是防篡改还是防泄露都有保障。但真正让它好用起来的,是接下来这个机制。

串联 ActiveRecord:serialize 的妙用

Rails 里有个 serialize 类方法,可以告诉模型某个字段在入库前和出库后应该经历怎样的转换。比如你可以直接声明一个字段存成 Hash 类型:

class User < ActiveRecord::Base
 serialize :preferences, Hash
end

user = User.new
user.preferences = {
 gender: 'male',
 age: 18
}
user.sa ve!

当你设置 serialize :preferences, Hash 时,Rails 会在写入前自动把 Hash 序列化成 YAML 字符串,读取后再反序列化回 Ruby 对象。这个流程其实就是我们想要的“自动处理”模型。

更灵活的是,Rails 允许你定义自己的 Serializer。只要实现 .load.dump 两个类方法,就可以完全控制序列化和反序列化的逻辑。类似这样:

class CustomerSerializer
 def self.load(value)
  value.to_s.blank? ? "" : JSON.parse(value)
 end

 def self.dump(value)
  (value || {}).to_json
 end
end

class User < ActiveRecord::Base
 serialize :preferences, CustomerSerializer
end

在这个基础上,把加密解密逻辑放进自定义 Serializer 里,就水到渠成了。

实战:字段加密 Serializer 实现

结合 ActiveSupport::MessageEncryptorserialize,我们直接实现一个能自动加密和解密的 Serializer:

class EncryptedStringSerializer
 def self.load(value)
  value.to_s.blank? ? '' : decrypt(value)
 end

 def self.dump(value)
  encrypt(value || '')
 end

 private

 def self.encrypt(value)
  encryptor.encrypt_and_sign(value)
 end

 def self.decrypt(value)
  encryptor.decrypt_and_verify(value)
 end

 def self.encryptor
  @encryptor ||= ActiveSupport::MessageEncryptor.new(Settings.message_encryptor_key)
 end
end

class UserAddress < ActiveRecord::Base
 serialize :phone, EncryptedStringSerializer
 serialize :first_name, EncryptedStringSerializer
 serialize :last_name, EncryptedStringSerializer
 serialize :country, EncryptedStringSerializer
 serialize :state, EncryptedStringSerializer
 serialize :city, EncryptedStringSerializer
 serialize :address1, EncryptedStringSerializer
 serialize :address2, EncryptedStringSerializer
 serialize :zipcode, EncryptedStringSerializer
end

这样,当 UserAddress 实例的任何一个字段被赋值时,.dump 会被触发,自动加密存储;从数据库读取时,.load 自动解密。业务代码里完全不需要关心加密细节。

可以改进的点

不过这个方案有两个地方值得再琢磨一下:

1. 加解密用的 KEY 是否过于简单?

这里直接用配置项 Settings.message_encryptor_key 初始化了加密器。生产环境中,密钥的管理最好能纳入更严格的体系,比如使用环境变量、密钥管理服务或者定期轮换策略。硬编码在配置里,一旦泄露就全线失守。

2. 针对现有数据,如何平滑过渡?

如果数据库里已经存了大量明文数据,直接加上加密 Serializer 会导致所有旧数据读取时解密失败。需要设计数据迁移脚本:分批读出来加密再写回去,或者采用读时兼容、写时加密的策略,逐步完成数据的更新。这在生产环境切换时需要格外小心。

本文转载于:https://www.jb51.net/article/129100.htm 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

产品推荐

热门关注