【BCrypt】BCryptを使ったRails+MongoDBでのパスワード暗号化

パスワードとかを暗号化する際にBCryptを良さげなので Rails+MongoDBでの導入方法から使用方法まで

やりたいこと

Rails+MongoDBでパスワードフィールド(RDBでいう属性、カラム)とか 生で保存したくないデータを暗号化したいとき

BCryptとは

認証で使用するパスワードを安全にハッシュ化するアルゴリズム。 SHA256等では暗号化として不足するため(下記参照)、 saltと呼ばれる短いランダムな文字列を末尾に加えて暗号化する。 レインボーテーブル(ハッシュ値に対して総当たりで平文を得ようとする)に対して強力のようです

BCryptのすすめ

よくあるHash関数アルゴリズムは(元々高速に計算することを意図していたのもあり)非常に高速に計算が可能であり、総当たり試行されてしまえば、現代のコンピュータスペックをもってすれば一瞬で解読されてしまいます。また、レインボーテーブルと呼ばれる、高速にHashから元の値を類推することが可能なアルゴリズムも存在し、Hash化では不足です。

インストール

Gemfileに下記を追加し、bundle installでインストールできます

# パスワード暗号化Gem
gem 'bcrypt', '~> 3.1.11'

model

app/models内の暗号化したいフィールド(属性、カラム)があるモデルについて 下記の様にhas_secure_passwordメソッドを使用します。

class Hoge
  # has_secure_passwordが存在しない。というエラーが発生したら追加します
  include ActiveModel::SecurePassword

  # パスワード暗号化
  has_secure_password

end

Hogeモデルにpassword_confirmationフィールドが追加され、 validateも自動で追加されます。 authenticateメソッドが使えるようになります

なおRDBの場合、password_digest属性の追加されたことにより マイグレーションが必要になります。 (MongoDB等のNoSQLの場合不要です)

ViewおよびControllersでの使用方法

View側でpasswordをform_tagで送り、Controllersでドキュメント(行、レコード)を追加することで こうすることでbcryptがpassword_digestフィールドに暗号化されたパスワードを入れます。 Controllers側では暗号化に関わる処理は特に何もする必要はないです。

以下ユーザ登録フォームでの使用方法例

スクリーンショット 2018-12-08 13.22.33.png

app/views/userCreate.erb

            <h4 class="">ユーザー登録</h4>
            <%= form_tag("/user/create") do%>
                    <p class ="">名前</p>
                    <input class="" name = "name">
                    <p class ="">Eメール</p>
                    <input class="" name = "email">
                    <p class ="">パスワード</p>
                    <input type="password" class="" name ="password">
                    <div class="">
                        <input type="submit" class="btn btn-primary" value="登録">
                     </div>
            <% end %>

/config/route.rb

post "/user/create" => "user#userCreate"

app/controllers/user_controller.rb

    def userSignUp
        @user = User.new
    end

パスワード認証方法

先ほどは暗号化したパスワードを格納しましたが、 今度はパスワードを画面入力した際など、画面から生のパスワードデータがきたときのControllers側の処理はauthenticateメソッドを利用します。

以下、ログイン画面を想定した使用例です

スクリーンショット 2018-12-08 13.21.21.png

/app/views/login.erb

 <%= form_tag("/user/login") do%>
   <p class="">ユーザ名</p>
    <input class="w-150" name="name">
   <p class="">パスワード</p>
    <input type="password" class="" name="password">
    <div class="">
      <input type="submit" class="btn btn-primary" value="ログイン">
    </div>

/config/route.rb

post "/user/login" => "user#userLogin"

app/controllers/user_controller.rb

    def userLogin
        @user = Hoge.find_by(name: params[:name])
        # @user.authenticateで入力されたパスワードを暗号化した後に
        # password_digestフィールドと比較
        if @user && @user.authenticate(params[:password])
            flash[:notice] = "ログインしました"
            redirect_to("/Fuga")
        else
            @errorMessage = "ログインに失敗"
            render("/login")
        end

    end

参照

Railsにおけるパスワードの扱い方(BCrypt)
BCryptのすすめ
どちらもありがとうございます。