Ruby,Railsの暗号化いろいろ

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

元気が出たら書く。

最後に

セキュリティ関係に関して調べて書いてみました。
まだどういった場合使うべきなのかいまいちよくわかってないのでそこを調べて実際の用途について調べてまた書きたいです。
おわり

コメントを残す

メールアドレスが公開されることはありません。