🔥

【Ruby】SecureRandomを使ってユーザー認証を強化する方法

2024/05/12に公開

はじめに

こんにちは、Takeです。都内の自社開発企業でエンジニアとして働いています。

本記事ではRubyの標準ライブラリであるSecureRandomを用いて、セキュアなユーザー認証に必要となるトークンを生成する方法について学習した内容を共有します。

前提

SecureRandomとは

(ざっくりと)推測されにくいランダムな数値や文字列を生成するためのツールのこと。

https://docs.ruby-lang.org/ja/latest/class/SecureRandom.html

https://qiita.com/colorrabbit/items/f65454105bb0e1cfbf74

トークンとは

一時的に生成されるランダムな文字列でユーザーを識別するために活用される。

ダイジェストとは

認証時に送られてきたデータを同じハッシュ関数で変換し、保存されたダイジェストと照合することで認証を行う。
サーバー側で保存される。

トークンとダイジェストの比較

特性 トークン ダイジェスト
使用目的 ユーザーのブラウザに一時的に保存され、認証に直接使用される。 データベースに保管され、トークンの照合に使用される。
生成方法 ランダムなデータ生成関数(SecureRandom.urlsafe_base64)などを使用して生成される。 ハッシュ関数(SHA-256)を使用してトークンから生成される。
安全性 ランダムに生成されるが、盗まれた場合はそのまま悪用される可能性がある。 ハッシュ化された形で保存されるため、盗まれても元のトークンを特定することは困難。

トークンの生成

SecureRandom.urlsafe_base64メソッドは安全なランダムトークンを生成する。このメソッドは、A-Z、a-z、0-9、"-"、"_"の64種類の文字からランダムに22文字の文字列を生成する。

irb(main):001> SecureRandom.urlsafe_base64
=> "TGYseMGxXvuG4tmD08MiAQ"
irb(main):002> SecureRandom.urlsafe_base64
=> "a_xN8Hw0BMuRHrGszl-CLA"
irb(main):003> SecureRandom.urlsafe_base64
=> "AUMBKxwWbV0eMGGEP2LNJg"

ダイジェストの生成

生成されたトークンはUser.digestメソッドを用いてハッシュ化され、このハッシュ化されたバージョン(ダイジェスト)がデータベースに保存される。これにより、もしトークンが何らかの方法で漏洩しても、実際のトークンを特定することは困難になる。

def remember
  self.remember_token = User.new_token
  update_attribute(:remember_digest, User.digest(remember_token))
end

このメソッドは、新しいトークンを生成してユーザーインスタンスのremember_tokenプロパティに保存した後、そのトークンのダイジェストをremember_digestフィールドに更新する。

ユーザーの認証プロセス

ユーザーがサイトに再訪した場合、保存されているクッキーからトークンを取り出し、送信されたトークンをハッシュ化してデータベース内のダイジェストと照合する。この流れでユーザーの認証が行われる。

rails console --sandbox
user = User.first
user.remember
  TRANSACTION (0.1ms)  SAVEPOINT active_record_1
  User Update (0.3ms)  UPDATE "users" SET "updated_at" = ?, "remember_digest" = ? WHERE "users"."id" = ?  [["updated_at", "2024-05-12 05:18:18.739100"], ["remember_digest", "$2a$12$RQayRzS/lv5Je8NDcycI9ut2uMn8uNDMWUZ.H0t1ixBXyRHFn6mYS"], ["id", 1]]
  TRANSACTION (0.0ms)  RELEASE SAVEPOINT active_record_1
=> true

このメソッドは、Userモデル内で新しいremember_tokenを生成し、そのトークンを使ってremember_digestを計算してデータベースに更新を行います。

user.remember_token
=> "eEpHwgjEMBzs3YVjoAEl6Q"

user.remember_digest
=> "RQayRza$12$0t1ixBXyRHFn6mYSyc0t1ixBXyRHFn6mYSycI9uS/lv5$2t2uMn"

まとめ

本記事を通じて、トークンとダイジェストを用いたユーザー認証の安全な方法を中心に解説してきた。SecureRandomを使った安全なトークン生成はセキュリティ基盤を強化する効果的な手段である。この概念を理解し、さらなるセキュリティ強化に取り組んでいきたい。

最後に

ここまで読んでいただきありがとうございました!
今回の記事が良かったと思ったらぜひ「いいね」を押していただけると嬉しいです 🎉

noteでも記事を執筆していますので、ぜひチェックしてみてください。
https://note.com/take_lifelog/n/n58df7ce7af6f

他にもこのようなことについて記載しているのでお読みいただければ幸いです。

https://zenn.dev/take_tech/articles/275e5f4242973d

https://zenn.dev/take_tech/articles/374817f256ec9d

最後までお読みいただき、誠にありがとうございました!

Discussion