RubyやRailsにおける暗号化について忘備録としてまとめました。
目次
Crypt
rubyで使える暗号化を行うもので暗号化されたものから元の文字列を求めることはできない。
使い方としては
str = 'hello'
str.crypt('secret_key')
で暗号化ができる。
OpenSSL::Cipher
調査中
message_verifier
remember meのトークンの実装に使われたりするらしい
暗号化することも暗号化されたものから元の文字列を求めることもできる
使い方は
remember_token = Rails.application.message_verifier('secret_key').generate({ token: 'i am bob' })
p remember_token
=> "BAh7BjoKdG9rZW5JIg1pIGFtIGJvYgY6BkVU--84c91772394d97fe0700d8e9cf4e84100f28f0ee"
p Rails.application.message_verifier('secret_key').verify(remember_token)[:token]
=> "i am bob"
message_encryptor
message_verifierと似た感じで使える。
crypt = ActiveSupport::MessageEncryptor.new('secret_key')
token = crypt.encrypt_and_sign('hello world')
p token
=> ArgumentError: key must be 32 bytes
となるので
len = ActiveSupport::MessageEncryptor.key_len
salt = SecureRandom.random_bytes(len)
key = ActiveSupport::KeyGenerator.new('secret_key').generate_key(salt, len)
crypt = ActiveSupport::MessageEncryptor.new(key)
token = crypt.encrypt_and_sign("i am bob")
p token
=> "ZGhtYnFlQTBkL2FlK2hOcG9aM1VhMHRpeDNwd2tUOGt0TlRDMHBNYlNpST0tLWtkcUI5VVFPNEViL2s2N3ZxOTU5Z1E9PQ==--1ff2c28f7b3686dde2bf1c00b88c23b115b76176"
p crypt.decrypt_and_verify(token)
=> "i am bob"
みたいに使う。
MD5
これは与えられた文字列を128bitの値に変換する。与えられた文字列を暗号化することはできるが暗号化されたものから元の文字列を求めることはできない。ハッシュ化というらしい。
使い方は
p Digest::MD5.digest('hello')
=> "]A@*\xBCK*v\xB9q\x9D\x91\x10\x17\xC5\x92"
p Digest::MD5.hexdigest('hello')
=> "5d41402abc4b2a76b9719d911017c592"
どうやらセキュリティ用途で使うのは安全とは言えなくなっているらしい。
bcrypt
bcryptはgemでユーザーのパスワードを暗号化したりログイン処理の時に使えるauthenticateメソッドを実装してくれたりする。
使い方は
gem 'bcrypt'
bundle installして
model/users.rbに
has_secure_password
と書くだけ。
この場合userモデルにpassword_digestというカラムがないと使えないので追加しておく。
これで暗号化を行ってくれる。
ログインしたい場合は
@user = User.find_by(email: params[:email])
if @user && @user.authenticate(params[:password])
session[:user_id] = @user.id
end
でOK
ユーザを作成する場合はpassword_digestに値を入れる必要はなく
password,password_confirmationという値を渡してあげれば大丈夫
encryptor
gemで暗号化もできるし復号化もできる。
使い方としては
gem 'encryptor'
bundle installして
require 'encryptor'
require 'securerandom'
secret_key = SecureRandom.random_bytes(32)
iv = SecureRandom.random_bytes(12)
encrypted_value = Encryptor.encrypt(value: "hello encryptor", key: secret_key, iv: iv)
p encrypted_value
=> "\xD5\xCC\x84G\xFBn\xCEw\xD6\x1D\x87\xD0\x00w\xDDdx\xB0\xF4\x97a\xC9\xA0\xD4\xA4\x88|\xDF\xC0\xAD7"
decrypted_value = Encryptor.decrypt(value: encrypted_value, key: secret_key, iv: iv)
p descrypted_value = "hello encryptor"
Stringクラスにインクルードすると便利っぽい
require 'encryptor/string'
secret_key = SecureRandom.random_bytes(32)
iv = SecureRandom.random_bytes(12)
String.include Encryptor::String
Encryptor.default_options.merge!(key: secret_key, iv: iv)
としてあげればあとは
password = "secure token"
p password.encrypt
=> "\x16\xEC\x9Ds\xE6\xB3.\x8D\xFF\x910|=O\xFBD\xD7$h\x9E6\x92\xAEo\xD6s\x97\xF7A\xEB\xA4"
encrypted_pass = password.encrypt
p encrypted_pass.decrypt
=> "secure token"
みたいにできる。
だが問題があって
Please be aware that Encryptor v2.0.0 had a major security bug when using AES-*-GCM algorithms.
By default You will not be able to decrypt data that was previously encrypted using an AES-*-GCM algorithm.
Please see the README and https://github.com/attr-encrypted/encryptor/pull/22 for more information.
らしい。
よくわからないけど AES-*-GCMを使った場合バグがあるみたいですね。
attr_encrypted
元気が出たら書く。
最後に
セキュリティ関係に関して調べて書いてみました。
まだどういった場合使うべきなのかいまいちよくわかってないのでそこを調べて実際の用途について調べてまた書きたいです。
おわり