web-dev-qa-db-ja.com

パスワードリセットトークンを適切に作成するにはどうすればよいですか?

私は長い間検索しましたが、パスワードリセットトークンを作成する方法を完全に説明する記事や投稿は実際には見つかりませんでした。

これまでに知っていること:

  • ランダムである必要があります。
  • そのハッシュはデータベースに保存する必要があります。
  • しばらくすると期限切れになります。

よくわからないこと:

  1. ランダムトークンを作成するには、暗号化方法を使用する必要がありますか? Is ノードのcrypto.randomBytes 十分ですか?
  2. トークンをハッシュするために、暗号方式(bcryptなど)を使用する必要がありますか?
  3. トークンに特定の情報(有効期限、UUIDなど)を含める必要がありますか?はいの場合、JWTは良い方法ですか?

プロセス全体は次のようになると思います。

  1. ランダムトークンを作成します。
  2. トークンをハッシュして、データベースに保存します。
  3. トークンをプレーンテキストでクライアントに送信します。
  4. 一度使用した場合、または一定の時間を過ぎても使用されない場合は、データベースから削除してください。
  5. トークンを使用する場合は、そのハッシュがデータベースのハッシュと一致するかどうかを確認してください。
  6. 一致した場合、ユーザーがパスワードをリセットできるようにします。それ以外の場合は、プロセスを拒否します。
5
yqlim

パスワードリセットトークンは、パスワードとあまり似ていません。これらは短期間で使い捨てであり、最も関連性が高いのは、ここではマシンによって生成され、メモリに記録できないことです。

  1. トークンを生成するには、暗号化された安全な乱数ジェネレータを使用する必要があります。 crypto.randomBytesで十分です。トークンの長さが十分であることを確認してください。 16バイト(128ビット)程度のものが機能するはずです。
  2. 「プリイメージ」(ハッシュ関数に入力される値、この場合はトークン)はランダムであるため、遅いハッシュを使用する必要はありません。遅いハッシュはブルートフォース保護のためです。パスワードは、(マシンの観点から)推測するのに時間がかかり、通常はかかりません。 128ビットのランダムな値は、用語の実際的な意味では総当たりではありません。 SHA-256または同様のものを1回実行するだけです。
  3. 悪いアイデア;それは物事を複雑にするだけです。代わりに、これらすべてのものをDBに保存してください。はい、JWTに置くことでステートレスに実行できますが、DBの方がはるかに理にかなっています。
    • いずれにしても、パスワードをリセットするには、DBを操作する必要があります。
    • とにかく、キャッシュをバイパスする必要があります。分散システムを使用している場合でも、すべてがこの変更を確認する必要があるため、ステートレスにしても意味がありません。
    • トークンを確認するために1回のDB読み取りを実行するだけで済みます(トークンの値が正しく、有効期限が切れていないため、単一のクエリで実行できます)。これは比較的まれなイベントです。すべてのリクエストでセッショントークンの検索を実行する必要があるのとは異なります。
    • JWTには有効期限がありますが、JWTを使い捨てにする便利な方法はありません(「これらのJWTは有効でなくなった」という状態を、それぞれが期限切れになるまでサーバーに保存する必要があります。これにより、JWTのポイントが失われます。パスワードリセットトークンDBに保存されているものは、検証時に削除することにより、使い捨てにすることができます(また、そうする必要があります)。
    • 必要に応じて、(使用されなかった)期限切れのトークンを定期的に削除するクリーンアップタスクを実行できます。ただし、DBでそれほど多くのスペースを使用することはありません(一度にユーザーごとに1つだけ有効にする場合は、ハッシュダイジェストとタイムスタンプ、またはハッシュダイジェスト、タイムスタンプ、および外部キーユーザーに対して複数のトークンを一度に有効にしたい場合は、Usersテーブル(両方に長所と短所があります)。
    • JWTは、単にチェックするだけと比較して、潜在的な脆弱性(署名キーを盗む、キーが安全に生成されておらず、バグが修正されてからローテーションされていない、誰かが発見する、JWTライブラリが脆弱であるなど)を抱えています。 DB(これは基本的にSQLi以外の脆弱性があると思いますが、これは回避方法を知っていると思います)。

あなたの基本的なプロセスは理にかなっています。

4
CBHacking

1.はい、トークンを生成するには暗号化方式を使用する必要があります。セキュリティに関連することを行うときは常に、暗号のランダム性を使用してください。はい、 crypto.randomBytes 結構です。 16バイトを使用します(少し少なくても問題はありませんが、トークンをクリックまたはコピーアンドペーストするだけでなく、絶対に入力する必要がない限り、リスクを冒さないでください)。 (16バイトは、Base64の24文字または32桁の16進数に変換されます。)

2. SHA-256やSHA-512などの暗号化ハッシュでトークンをハッシュします。ここではパスワードハッシュは必要ありません。bcryptなどのパスワードハッシュは、入力が人間が覚えているパスワードである場合に使用され、入力がランダムに生成された十分に少ない文字列である場合は役に立ちません。パスワードハッシュの使用は少し難しく、処理速度も非常に遅いため、ここでは必要ありません。

3.トークンに情報を追加することに利点はないようです。有効期限やトークンの目的などの情報は、いずれにしてもデータベースに存在する必要があります。