Rails实现字段加密存储
程序员文章站
2022-06-24 13:36:15
方案
存储前,加密后再存储到数据库
读取后,利用 key 进行解密
实现
activesupport::messageencryptor 是 rails 基于...
方案
存储前,加密后再存储到数据库
读取后,利用 key 进行解密
实现
activesupport::messageencryptor 是 rails 基于 openssl 封装实现的一个类,可用于对一个对象进行加密、解密操作。例如:
salt = securerandom.random_bytes(64) key = activesupport::keygenerator.new('password').generate_key(salt) # => "\x89\xe0\x156\xac..." crypt = activesupport::messageencryptor.new(key) # => #<activesupport::messageencryptor ...> encrypted_data = crypt.encrypt_and_sign('my secret data') # => "nlfbttmwouv5ula1qlnen2xky2d6ethywwh..." crypt.decrypt_and_verify(encrypted_data) # => "my secret data"
serialize 是 rails activerecord 里的一个类方法,可用于执行一个 column 如何存储到数据库,以及从数据库读取出来后要如何处理,例如:
class user < activerecord::base serialize :preferences, hash end user = user.new user.preferences = { gender: 'male', age: 18 } user.save!
另外,rails 还允许自定义 serizlizer,使得开发者能够自行决定如何做进行序列化和反序列化。例如:
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,使得我们能够进行对字段进行加密存储,同时读取出来时能够自行进行解密。
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
可以改进的点
加解密用的 key 是否过于简单?
针对现有数据,如何平滑过渡?