2014-03-06 [長年日記]
_ omniauth-identity
OmniAuth、twitter認証やfacebook認証が簡単に作れて便利ですね。omniauth-identity gem を使うと自前のパスワード認証も簡単につくれます。AsciiCast に解説もあっていたれりつくせり。
メールとパスワードの入力Webページは omniauth-identity が自動でつくってくれて便利ですが、APIからユーザーを作りたい場合にコントローラでどうすればいいのか調べたのでメモ。難しいことは何もなく、Identityモデルでpassword に代入する際にpassword_digestを計算して入れてるだけだった。
なので、
i = Identity.new(name: "igaiga", email:"igaiga@example.com", password: "igaigapass")
これでpassword_digest が代入されてる。あとは i.save! すればOK。
実際にやってるのは omniauth-identity gemの以下。
OmniAuth::Identity::SecurePassword::InstanceMethodsOnActivation#password=
def password=(unencrypted_password)
@password = unencrypted_password
if unencrypted_password && !unencrypted_password.empty?
self.password_digest = BCrypt::Password.create(unencrypted_password)
end
end
ところで、saltはないんですね。最近の認証システムにはsaltないなー、と思って調べてみた。
ここに詳しく書いてある。簡単に言うとこんな感じ。
- BCrypt::Password.create(unencrypted_password) をつかっている。
- これはsaltを保存しなくてよい仕組み。(中で自動生成)
- そもそもsalt は何のためにあるかと言うと、攻撃者が総当たりで攻撃したときに時間がかかるようにするため。
- 暗号化された文字列が流出したときの話
- paswordとsaltを1つずつずらして暗号化して・・・を繰り返させる
- そこで、攻撃者が計算するときに(saltがあったときよりも)十分に遅ければ、別途saltを保存しなくても良いはず
- 普通のhash(MD5とか)は遅くは設計されてない。速く計算されてしまう。
- bcrypt は暗号化計算が十分に遅い。秒間450個のパスワードしか生成できない。(MD5だと約140,000個)
なるほど。どれどれ。
require 'bcrypt'
start = Time.new
100.times { |i| BCrypt::Password.create(i) }
finish = Time.now
p "#{finish - start} sec"
実行させたら100個暗号化するのに 6.247545 sec だった。確かにかなり遅くできてる。
3/7 追記: Omniauth-identity、ascii cast に従ってname, emai, password_digestを作ったけど、表示しなければname要らないか。