Как реализовать пароль Reset Ссылка

В настоящее время у меня есть система, в которой, если пользователь забыл свой пароль, он может reset, нажав ссылку на забытый пароль. Они будут отправлены на страницу, где они войдут в свое имя пользователя/адрес электронной почты, а затем электронное письмо будет отправлено пользователю, я хотел бы знать, как я могу реализовать ссылку на пароль reset в письме, чтобы как только пользователь нажмет на он переводится на страницу, которая позволит им reset их пароль.

Это код в моем контроллере

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: ' [email protected] + ' @' + cast (getDate() as varchar) + ' ' ;
EXEC msdb.dbo.sp_send_dbmail 
@profile_name='Test',
@[email protected],
@subject='Password Reset',
@[email protected]
END 

GO

Ответ 1

Создайте таблицу с такой структурой, как

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

Затем в вашем коде, когда пользователь нажимает кнопку пароля reset, вы создадите случайный токен, затем поместите запись в эту таблицу с хешированным значением этого token и датой истечения чего-то вроде DATEADD(day, 1, GETDATE()) и добавляет значение токена на URL-адрес, который вы отправляете пользователю по электронной почте для пароля reset.

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

На странице пароля reset вы берете имя пользователя и токен, прошедшие через, хеш-токен, затем сравниваете это с таблицей ResetTickets, и если дата истечения еще не прошла, а токен еще не был использован затем возьмите пользователя на страницу, которая позволяет им вводить новый пароль.

Осторожно о:

  • Удостоверьтесь, что срок действия маркера истекает, не позволяйте электронной почте от двух лет назад reset пароль.
  • Обязательно отметьте используемый токен, не позволяйте другим пользователям компьютера использовать историю браузера для паролей пользователей reset.
  • Убедитесь, что вы произвольно создаете случайный токен. Не используйте Rand и используйте его для генерации токена, два пользователя, которые reset в то же время получат один и тот же токен (я мог бы reset мой пароль и ваш пароль одновременно использовать мой токен reset ваша учетная запись). Вместо этого сделайте статический RNGCryptoServiceProvider и используйте метод GetBytes, из которого класс является потокобезопасным, поэтому вам не нужно беспокоиться о два потока, использующих один и тот же экземпляр.
  • Обязательно параметризовать ваши запросы. В вашем текущем коде, если я набрал идентификатор пользователя '; delete dbo.[USERS] --, он удалит всех пользователей в вашей базе данных. См. Связанное сообщение SO для получения дополнительной информации о том, как его исправить.
  • Убедитесь, что вы используете маркер, ваша страница passwordReset принимает только версию unhashed, и вы никогда не храните неизвестную версию где-либо (включая журналы электронной почты исходящих сообщений для пользователей). Это предотвращает доступ злоумышленника к доступу к базе данных от создания маркера для другого пользователя, считывая значение, которое было отправлено в электронном письме, а затем отправляет одно и то же значение (и, возможно, получает доступ к пользователю-администратору, который может делать больше материала чем просто прочитанные значения).