web-dev-qa-db-ja.com

「パスワードを忘れた」機能を実装するには?

私のプロジェクトでは、「forgot password」機能が必要です。

この種の機能を実装する方法はまだよくわからないので、インターネットで「ベストプラクティス」を見つけたいと思っていましたが、この非常に一般的な機能のすべての重要な側面を扱う便利なものが見つかりませんでした。


これについての私自身の考えはかなり単純です。

ユーザーが自分のパスワードを変更したい場合は、「パスワード変更要求」に添付された一意のトークンuniqueTokenForTheUserを作成できます。これは、本質的に、バックエンドが要求を送信した正しいユーザーかどうかを識別するための識別子になります。

したがって、たとえば、メールを生成/送信して[email protected]リンクあり

http://www.example.com/changePassword?token=uniqueTokenForTheUser

uniqueTokenForTheUserは、一定の間隔でスレッドによってチェックされるテーブルに格納され、ユーザーが実際にパスワードを変更しなかった場合に備えて、トークンの有効期限が切れるとレコードが削除されます。

これは私にはかなり簡単に聞こえますが、「ベストプラクティス」がそこにあるかどうかを再確認したかったのです。その特定のトークンの生成と削除に関しては。

記事やチュートリアルへの提案や参照は大歓迎です!


コメントによって提案された追加リンク:

71
displayname

これだけにHTTPSを使用してから、実装の詳細に進みます。

まず第一に、あなたは ser enumeration から保護したいでしょう。

つまり、ユーザーが存在するかどうかをページで明らかにしないでください。これは電子メール自体でのみ開示されるべきです。

第二に、あなたは リファラー漏れ を避けたいでしょう。ターゲットリンクに外部リンクまたは外部リソースが存在しないことを確認します。これを軽減する1つの方法は、最初のリンクをたどった後にリダイレクトして、トークンがクエリ文字列に含まれないようにすることです。何か問題が発生した場合(データベースが一時的にダウンしている場合など)に標準エラーテンプレートが表示されている場合は、外部参照が含まれていると、トークンが漏洩する可能性があります。

CSPRNGで128ビットのエントロピーを含むトークンを生成します。このサーバー側をSHA-2を使用して保存し、リセットテーブルのデータ漏えいの脆弱性により、攻撃者がパスワードをリセットできるようにします。塩は必要ないことに注意してください。これらのトークンは、しばらくして(たとえば数時間)期限切れにします。

メールリンクでハッシュ化されていないトークンをユーザーに提供するだけでなく、ユーザーが手動でページに移動してからトークン値を貼り付けるオプションを提供します。これにより、クエリ文字列の値がブラウザの履歴に記録されたり、デフォルトでプロキシやサーバーのログに記録されたりするのを防ぐことができます。

オプションで、パスワードのリセットを開始したセッションのセッションIDがリンクをたどったものであることを確認したい場合があります 。これは、攻撃者がユーザーのメールにアクセスできるアカウントを保護するのに役立ちます(たとえば、メールアカウントへのアクセスが制限されたすべてのルールのクイック転送を設定します)。ただし、実際にこれが行うのは、ユーザーがリセットを要求した後に攻撃者が日和見的になるのを防ぐことです。攻撃者が特定のサイトをターゲットにしたい場合、攻撃者は犠牲者に独自のリセットトークンを要求することができます。

パスワードがユーザーの選択のいずれかにリセットされたら、トークンを期限切れにし、ユーザーにメールを送信して、攻撃者が何らかの方法でパスワードをリセットできた場合に備えて、これが発生したことを通知する必要があります(必ずしも制御する必要はありません)。メールアカウントの)-多層防御。 現在のセッションIDをローテーションし、このユーザーアカウントのその他のIDを期限切れにする 。これにより、ユーザーが再度ログインする必要がなくなり、攻撃者によって無効にされたセッションもクリアされます。ただし、一部のユーザーはサイトをログアウトさせて、パスワードが実際にリセットされたことを簡単に確認できるようにします。ログインページにリダイレクトすることで、一部のパスワードマネージャーはログインURLと新しいパスワードを保存することができますが、多くの場合、リセットページから新しいパスワードを検出しています。

また、リセットメカニズムと変更通知について、他の帯域外オプションを検討することもできます。たとえば、SMSまたは携帯電話のアラート。

69
SilverlightFox

あなたの考え方は正しい方向に進んでいます。ただし、パスワードを忘れた場合の機能の流れを1つ前に説明することをお勧めします。 誰かが自分のパスワードを忘れたと主張している場合は、この人が本当にパスワードを開始するアカウントの所有者であることを確認する必要があります回復手順。

以下のフローは、ウェブサイトなど、ユーザーが自分でサインアップできるサービスを想定しています(つまり、登録済みのメールやユーザー名のリストは、サインアップ機能を使用して作成できます)。

ステップ1:ユーザーを特定

  1. [エラー、パスワードを忘れました]リンクをクリックして、ユーザー名とメールアドレスを入力するフォームをユーザーに提示します(オプションで、メールアドレスに関するヒントを「s ..... @」の形式で提供しますo .... com ');
  2. 入力したメールアドレスが入力したユーザー名に属しているかどうかを通知します(はいまたはいいえ)。
  3. 入力したユーザー名とパスワードが一致する場合は、次の手順に進みます。

ステップ2:リカバリ手順を開始

  1. ランダムな回復トークンを生成します(128ビットで十分です)。
  2. このトークンのハッシュ(パスワードハッシュアルゴリズムを使用して作成されたもの)とその作成タイムスタンプをデータベースに保存します。
  3. パスワードの変更フォームへのリンク(回復トークンを含む)が記載された電子メールをユーザーに送信します。パスワード変更フォームのURLはHTTPSである必要があります。
  4. パスワードの変更要求を受け取ったら、次を確認します:[1]。トークンの有効性(現在の時間と比較した作成時間を使用して、通常は10分の時間枠で十分です)。 [2]。提示されたトークンが正しい場合(トークンをハッシュし、パスワードの場合と同様に、結果のハッシュをデータベース内のハッシュと比較します);
  5. すべてのチェックに合格した場合は、次のステップに進みます。

ステップ3:パスワードを更新する

  1. このユーザーのために保存した可能性のあるすべての「記憶」情報を破棄します。
  2. このユーザーに関連付けられているすべてのアクティブなセッションを破棄します。
  3. ユーザーのパスワードを更新します。
  4. 必要に応じて、変更を通知するメールをメールアドレスに送信します。
  5. ユーザーをログインさせます。
13
Jacco

あなたのアプローチでベストプラクティスに近づいています。小さな追加は次のようになります:

  • ユーザー名をトークンから単に差し引くのではなく、トークンと一致させる必要がある場合があります。

  • Httpではなくhttpsを使用する必要があります。

他の質問:

  • 生成について:それらを生成する通常の方法はUUIDを使用することですが、コメントが指摘するように、完全にランダムで十分に長い文字列を使用する必要があります。

  • 削除に関して:提案したように、定期的に古い未使用のトークンをクリーンアップできます。たぶん、メールが通常のメールのグレーリストを通過できるような時間枠を使用してください。 15分。

7
Tobi Nary

これに関するいくつかの考え:

  • 電子メールは本質的に安全ではありません。トークンは、攻撃者によってサーバーとユーザーの受信トレイの間の任意の場所で盗まれる可能性があります。可能であれば、SMSなどの別の通信媒体の使用を検討してください。
  • 電子メールでアクセスする場合、復元リンクはHTTPではなくHTTPS上にある必要があります。少なくともプロセスのその部分は暗号化できます。
  • ユーザー列挙攻撃を防ぐには、同じメッセージを表示するか、ユーザーが入力したユーザー名/メールアドレスが存在するかどうかを確認する必要があります。 (少なくとも、ユーザーがユーザー名のみを入力した後に電子メールを表示するミスをしないでください。)
  • 適切な疑似乱数ジェネレータと長いトークンを使用します。誰もトークンを推測できないはずです。トークンの推測を難しくするには、ユーザーがユーザー名とトークンの両方を入力する必要があります。 (ユーザー名またはIPごとに)試行回数を制限すると、総当たり攻撃も防止されます。おそらくCAPTCHAも?
  • トークンの有効期間を制限したい。メールがフィルターに詰まっていると遅くなるかもしれませんが、誰もが30分以上言う必要がある理由はわかりません。
  • アカウントが復元されたら、そのアカウントのすべての古いセッションを終了します。アカウントが危険にさらされているため、ユーザーがアカウントを復元する可能性があり、攻撃者はログアウトする必要があります。
  • 使い捨てトークンのみを送信し、新しいパスワードは送信しないでください!パスワードを電子メールで送信しないでください。
  • トークンの使用は1回だけにしてください!使用後すぐに削除してください(ユーザーが実際にパスワードを変更していない場合でも)。

このトピックの詳細については、 トロイハント をお勧めします。

4
Anders