どちらが良いですか?
暗号化されたトークン内にユーザーIDと有効期限を含む改ざん防止された暗号化パスワードリセットトークンを作成します。
ランダムなトークンを生成し、ユーザーIDと有効期限と共にデータベースに格納します。ユーザーがリンクをクリックしたときにトークンを検索します。
#2で確認できる利点は、これらのトークンを制御できることです。もっと早く期限切れにしたいなら、できます。私が#1で目にする問題は、送信するトークンが本当に安全で改ざん防止されていることを確認することです。あなたは完全に暗号を台無しにしないことに依存しています。
ASP.NET 2.0には、パスワードリセットトークンを生成するための組み込みメソッドがありますか?
情報をまったく含まないランダムトークンを作成し、それをデータベース内でユーザー名と有効期限にリンクすることは、最善の解決策です。
暗号化(およびハッシュ)は、絶対に送信する必要のあるデータを格納および転送するために使用されます。暗号化されているかどうかに関係なく、データを送信せずに何かを行う方法があり、同等の機能とセキュリティが提供されている場合は、その方法を使用する必要があります。言い換えれば、暗号化はデータを保護するための最後の手段であるべきです。
これらのトークンは同等のパスワードであるため、同様の要件を満たす必要があります。しかし、断然、最大のものは、それが敵によって勝手に推測されてはならないということです。したがって、ランダムデータと区別できません。
データをエンコードするときは、明らかに暗号化する必要があります。さて、これはおそらく自分自身を転がす、または少なくとも暗号プリミティブを自分で組み立てるある程度のレベルを含むでしょうが、それはおそらく間違っているでしょう(参照: Daveにならないでください )。
つまり、これは、最も安全で簡単なソリューションは、非常にランダムなトークンを作成し、ハッシュ化/ソルトしてデータベースに保存することと、そのトークンのIDを保存することです。 IDとトークンを結合し、それを16進数またはBase32にシリアル化して、ユーザーに送信します。トークンが戻ってきたら、IDを使用してデータベースからトークン/ソルトを取得し、トークンの残りの部分をハッシュして、一致するかどうかを確認します。
トークンは人の電子メールに含まれるため、トークンについていくつかの追加事項を確認する必要があります。
有効期限をトークンにエンコードしてHMACを使用することもできますが、通常、パスワードのリセットには特定のURLへのアクセスが含まれます。通常、ユーザーの操作を簡単にするために、GETフィールドとしてURLにトークンを含めます。
URLを比較的小さく、印刷可能な文字のみで構成したい場合、タイムスタンプを整数としてエンコードし、固定幅の設定を使用します。これは、ユーザー、有効期限、およびMACを指定する必要があります。信頼できると思いますが、なんらかのコーディング作業が必要です。
とにかく、データベースのパスワードをヒットする必要があり、ランダムな固定幅の値をエンコードすることはまったく考えないので、私はそれでうまくいきます。他のすべてが等しい(そして私はそれがかなり等しいと思う)ので、簡単に勝ちます。追加ボーナス:CPU使用率の低下。
それは共通のテーマです。シナリオ#1は、シナリオ#2よりもストレージ最適化です。 #2では、乱数値をサーバー側で生成して保存する必要があります。これにより、必要なすべてのコントロールが得られますが、データベースに追加の列などが必要です。シナリオは、このストレージ要件をクライアント側でオフロードします。クライアントは信頼できないため、リンクに整合性チェックを追加する必要があります。つまり、 [〜#〜] mac [〜#〜] ;リセットリンクにはユーザーから秘密にしておく必要があるものは何もないため(ユーザーはすでに自分の名前を知っており、パスワードのリセットを要求したとき)、悪意のあるクライアントが偽物を作成するのを防ぎたいので、暗号化は必要ありません。リセットリンク、したがってMAC。
したがって、シナリオ#1のトークンの内容には、パスワードリセットポリシーを適用するために必要なすべてのデータを含める必要がありますが、サーバーに保存しないことを選択しました。これは、ユーザー名とタイムスタンプ(パスワードリセットプロセスがトリガーされた時刻、または有効期限)を意味します。ユーザーがリセットリンクを何度も再利用できないようにする場合は、MACへの入力に(必ずしもトークンではない)以前のパスワードのハッシュを含めることができます。
MACの計算と検証は多くのリソースを必要としません。おそらくランダムトークンを生成してデータベースに保存するよりも少し少ないでしょう(データベースアクセスは暗号よりもかなり高価になります)。ただし、この影響はとにかく無視できる可能性があります(データベースは高速です)。シナリオ#1の短所は、サーバーに秘密鍵を保持し、フロントエンド間で共有する必要があることです(複数ある場合)。再起動に対して復元力があるため、RAMのみの鍵ではありません。サーバーの再起動時にすべてのパスワードリセットリンクを無効にする準備ができていない限り)、そしてもちろん、盗聴から安全です。
ランダムトークン(シナリオ#2)はおそらくより簡単ですが、必要に応じて誤解するのが難しくなります。それはそれをお勧めするのに十分な理由です。
Troy Huntのこの記事をお勧めします: 安全なパスワードリセット機能の構築について知りたいことすべて
以下は、リセットトークンの処理方法について彼が言っていることです。
私たちがやりたいことは、リセットURLの一部としてメールで送信できる一意のトークンを作成し、ユーザーのアカウントと一緒にサーバー上のレコードと照合して、メールアカウントの所有者が実際にリセットしようとしていることを確認することですパスワード。たとえば、トークンは「3ce7854015cd38c862cb9e14a1ae552b」であり、リセットを実行しているユーザーのIDとトークンが生成された時刻(後でさらに詳しく)とともにテーブルに保存されます。メールが送信されると、「Reset /?id = 3ce7854015cd38c862cb9e14a1ae552b」などのURLが含まれ、ユーザーがこれをロードすると、ページはトークンの存在を確認し、その結果、ユーザーのIDを確認し、パスワードに変更されます。
OWASP wikiにもチートシートがあります。 パスワードを忘れた場合のチートシート ですが、情報をデータベース。