1. ホーム
  2. スクリプト・コラム
  3. ルビートピックス

Railsにフィールド暗号化ストレージを実装

2022-01-03 07:45:24

スキーム

データベースに保存する前に暗号化する。
読み取り後、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のクラスメソッドで、カラムをデータベースに格納する方法と、データベースから読み込んだ後の処理を強制するために使うことができます。

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

user = User.new
user.preferences = {
 gender: 'male',
 age: 18
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



これを元に、フィールドを暗号化し、読み出すときに復号化できるようなシリアライザーを独自に実装すればよいのです。

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がシンプルすぎるのでは?
既存データの移行をスムーズに行うには?