web-dev-qa-db-ja.com

パスワードのリセットリンクを実装するにはどうすればよいですか

私は現在、ユーザーがパスワードを忘れた場合に、パスワードを忘れた場合のリンクをクリックしてパスワードをリセットできるシステムを持っています。ユーザー名/メールアドレスを入力したページに移動し、ユーザーにメールが送信されます。ユーザーがリンクをクリックすると、パスワードリセットリンクをメールに実装する方法を知りたいと思いました。 /彼女は、パスワードをリセットできるページに移動します。

これは私のコントローラーのコードです

public ActionResult ForgotPassword()
        {
           //verify user id

            string UserId = Request.Params ["txtUserName"];
            string msg = "";
            if (UserId == null) 
            {
                msg = "You Have Entered An Invalid UserId - Try Again";
                ViewData["ForgotPassword"] = msg;
                return View("ForgotPassword");
            }

            SqlConnection lsql = null;
            lsql = DBFactory.GetInstance().getMyConnection();

            String sqlstring = "SELECT * from dbo.[USERS] where USERID = '" + UserId.ToString() + "'";
            SqlCommand myCommand = new SqlCommand(sqlstring, lsql);
            lsql.Open();
            Boolean validUser;         
            using (SqlDataReader myReader = myCommand.ExecuteReader())
            {

                validUser = false;
                while (myReader.Read())
                {
                    validUser = true;

                }
                myReader.Close();
            }
            myCommand.Dispose();  


            if (!validUser) 
                  {
                msg = "You Have Entered An Invalid UserId - Try Again";
                ViewData["ForgotPassword"] = msg;
                lsql.Close();
                return View("ForgotPassword");
            }

            //run store procedure


            using (lsql)
            {
                SqlCommand cmd = new SqlCommand("Stock_Check_Test.dbo.RESET_PASSWORD", lsql);
                cmd.CommandType = CommandType.StoredProcedure;

                SqlParameter paramUsername = new SqlParameter("@var1", UserId);

                cmd.Parameters.Add(paramUsername);


                SqlDataReader rdr = cmd.ExecuteReader();
                while (rdr.Read())
                {
                    if (Convert.ToInt32(rdr["RC"]) == 99)
                    {
                        msg = "Unable to update password at this time";
                        ViewData["ForgotPassword"] = msg;
                        lsql.Close();
                        return View("ForgotPassword");  

                    }
                }
            }


            msg = "new password sent";
            ViewData["ForgotPassword"] = msg;
            lsql.Close();
            return View("ForgotPassword");
        }

これは、ユーザーに電子メールを送信する現在のストアドプロシージャです

ALTER PROCEDURE [dbo].[A_SEND_MAIL]
    @var1 varchar (200), -- userid
    @var2 varchar (200) -- email address
AS
BEGIN
declare @bodytext varchar(200);
set @bodytext = 'Password Reset for user: ' +@var1 + ' @' + cast (getDate() as varchar) + ' ' ;
EXEC msdb.dbo.sp_send_dbmail 
@profile_name='Test',
@recipients=@var2,
@subject='Password Reset',
@body=@bodytext
END 

GO
13

次のような構造を持つテーブルを作成します

create table ResetTickets(
    username varchar(200),
    tokenHash varbinary(16),
    expirationDate datetime,
    tokenUsed bit)

次に、ユーザーがパスワードのリセットボタンをクリックすると、コードでランダムトークンが生成され、そのtokenのハッシュ値とDATEADD(day, 1, GETDATE())のような有効期限を持つエントリがそのテーブルに配置されます。そして、パスワードリセットページのためにユーザーに電子メールで送信するURLにそのトークン値を追加します。

www.example.com/passwordReset?username=Karan&token=ZB71yObR

パスワードリセットページで、渡されたユーザー名とトークンを取得し、トークンを再度ハッシュしてから、それをResetTicketsテーブルと比較します。有効期限がまだ過ぎておらず、トークンがまだ使用されていない場合は、ユーザーが新しいパスワードを入力できるページに移動します。

注意事項

  1. トークンの有効期限が切れていることを確認してください。2年前のメールでパスワードをリセットしないでください。
  2. トークンに使用済みのマークを付けてください。コンピューターの他のユーザーがブラウザーの履歴を使用して他のユーザーのパスワードをリセットしないようにしてください。
  3. ランダムトークンを安全に生成するようにしてくださいRandを使用せず、それを使用してトークンを生成します。同時にリセットした2人のユーザーは同じトークンを取得します(パスワードとパスワードを同時にリセットしてから、トークンを使用してリセットできます)貴方のアカウント)。代わりに、静的 RNGCryptoServiceProvider を作成し、そこからGetBytesメソッドを使用します。クラスはスレッドセーフなので、同じインスタンスを使用する2つのスレッドについて心配する必要はありません。 。
  4. 必ず クエリのパラメータ化ユーザーIDを入力した場合は現在のコードで'; delete dbo.[USERS] --データベース内のすべてのユーザーを削除します。修正方法の詳細については、リンクされたSOの投稿を参照してください。
  5. 必ずトークンをハッシュしてください。passwordResetページはハッシュされていないバージョンのみを受け入れ、ハッシュされていないバージョンをどこにも保存しないでください(メールを含む)ユーザーへの送信メッセージのログ)。これにより、データベースへの読み取りアクセス権を持つ攻撃者が他のユーザーのトークンを作成し、電子メールで送信された値を読み取ってから、同じ値を自分で送信することを防ぎます(そして、より多くのことを実行できる管理者ユーザーにアクセスできる可能性があります)値を読み取るだけではありません)。
29