私は現在、ユーザーがパスワードを忘れた場合に、パスワードを忘れた場合のリンクをクリックしてパスワードをリセットできるシステムを持っています。ユーザー名/メールアドレスを入力したページに移動し、ユーザーにメールが送信されます。ユーザーがリンクをクリックすると、パスワードリセットリンクをメールに実装する方法を知りたいと思いました。 /彼女は、パスワードをリセットできるページに移動します。
これは私のコントローラーのコードです
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
次のような構造を持つテーブルを作成します
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
テーブルと比較します。有効期限がまだ過ぎておらず、トークンがまだ使用されていない場合は、ユーザーが新しいパスワードを入力できるページに移動します。
注意事項:
Rand
を使用せず、それを使用してトークンを生成します。同時にリセットした2人のユーザーは同じトークンを取得します(パスワードとパスワードを同時にリセットしてから、トークンを使用してリセットできます)貴方のアカウント)。代わりに、静的 RNGCryptoServiceProvider
を作成し、そこからGetBytes
メソッドを使用します。クラスはスレッドセーフなので、同じインスタンスを使用する2つのスレッドについて心配する必要はありません。 。'; delete dbo.[USERS] --
データベース内のすべてのユーザーを削除します。修正方法の詳細については、リンクされたSOの投稿を参照してください。passwordReset
ページはハッシュされていないバージョンのみを受け入れ、ハッシュされていないバージョンをどこにも保存しないでください(メールを含む)ユーザーへの送信メッセージのログ)。これにより、データベースへの読み取りアクセス権を持つ攻撃者が他のユーザーのトークンを作成し、電子メールで送信された値を読み取ってから、同じ値を自分で送信することを防ぎます(そして、より多くのことを実行できる管理者ユーザーにアクセスできる可能性があります)値を読み取るだけではありません)。