Rails: 文字列型カラムの暗号化
外観
目的
MessageEncryptorでActiveRecordの文字列型カラムを暗号化します。
環境
macOS 10.15.5
Ruby 2.7.1
Rails 6.0.3.2
Yarn 1.22.4
Node 13.12.0
参照
ActiveSupport--MessageEncryptor
Railsで透過的にカラム暗号化 - Qiita
リポジトリ
https://github.com/usutani/try_crypt
モデル
addressとnameを暗号化します。
手順
rails new -TM --skip-active-storage try_crypt
cd try_crypt
saltを秘匿情報に追加します。
bin/rails secret | pbcopy
EDITOR="vim" bin/rails credentials:edit
salt: <bin/rails secret で生成した文字列>
bin/rails credentials:show
コンソールで動作確認します。
bin/rails c
# MessageEncryptorを生成する。
salt = Rails.application.credentials.salt
key_len = ActiveSupport::MessageEncryptor.key_len
key = Rails.application.key_generator.generate_key(salt, key_len)
crypt = ActiveSupport::MessageEncryptor.new(key)
# 暗号化した文字列を復号できることを確認する。
encrypted_data = crypt.encrypt_and_sign('my secret data')
crypt.decrypt_and_verify(encrypted_data)
bin/rails g scaffold Member name address
bin/rails db:migrate
class Member < ApplicationRecord
after_initialize :decrypt_columns
before_save :encrypt_columns
def decrypt_columns
return if new_record?
crypt = message_encryptor
self.name = crypt.decrypt_and_verify(name)
self.address = crypt.decrypt_and_verify(address)
end
def encrypt_columns
crypt = message_encryptor
self.name = crypt.encrypt_and_sign(name)
self.address = crypt.encrypt_and_sign(address)
end
def message_encryptor
salt = Rails.application.credentials.salt
key_len = ActiveSupport::MessageEncryptor.key_len
key = Rails.application.key_generator.generate_key(salt, key_len)
ActiveSupport::MessageEncryptor.new(key)
end
end
bin/rails c -s
m = Member.create!(name: 'foo', address: 'bar')
m.name # => "暗号化された文字列"
m.reload
m.name # => "foo"
m.name_was # => "暗号化された文字列"
m.name = 'BAZ'
m.save
m.reload
m.name # => "BAZ"
モジュール化してみます。※後学のために
module ColumnEncryptor
extend ActiveSupport::Concern
included do
after_initialize -> { decrypt_columns(crypt_col_names) }
before_save -> { encrypt_columns(crypt_col_names) }
end
def crypt_col_names
raise NotImplementedError
end
def decrypt_columns(col_names)
return if new_record?
crypt = message_encryptor
col_names.each do |col_name|
self[col_name] = crypt.decrypt_and_verify(self[col_name])
end
end
def encrypt_columns(col_names)
crypt = message_encryptor
col_names.each do |col_name|
self[col_name] = crypt.encrypt_and_sign(self[col_name])
end
end
def message_encryptor
salt = Rails.application.credentials.salt
key_len = ActiveSupport::MessageEncryptor.key_len
key = Rails.application.key_generator.generate_key(salt, key_len)
ActiveSupport::MessageEncryptor.new(key)
end
end
class Member < ApplicationRecord
include ColumnEncryptor
def crypt_col_names
%i[name address]
end
end
bin/rails s
以上です。
この記事が気に入ったらサポートをしてみませんか?