2009-12-31 52 views
25

我正在尋求在我的網站上實現「忘記密碼」功能。我喜歡將包含一段時間後過期的臨時一次性使用URL的電子郵件發送給用戶的選項。生成臨時URL來重置密碼

我已經看過以下頁面來獲得這些想法,但我不知道如何使用ASP.NET和C#實現這一點。正如用戶所指出的那樣,如果我可以在不將這些信息存儲在數據庫中的情況下實現這一點,那將是理想的。請指教。

Password reset by emailing temporary passwords

謝謝。

回答

-2

根據您的需求,您可以加密信息,並以類似於以下格式

(UserId)-(ExpireDate) 

加密數據的格式,使該鏈接,然後對數據進行解密,並從那裏採取行動...

原油,但最有可能使用的,並且不需要使用DB

+29

將任何數據包含到密碼重置令牌是一種不好的做法。事件是否加密。知道該算法的黑客即使無法訪問用戶的郵箱,也可以爲任何用戶重置密碼。 – 2012-10-04 08:43:34

+3

-1。這個想法在某種意義上是好的,但不應該使用它,因爲Slava在之前的評論中解釋了安全問題。 – Mohayemin 2013-03-07 04:34:08

+5

@SlavaNadvorny黑客也需要知道加密算法的關鍵。你可以假設,如果黑客有權訪問加密密鑰,他可能也可以訪問存儲的哈希值,所以是的,這種技術似乎仍然是一個好主意。 – Guillaume 2013-03-22 12:42:47

1

在這裏,你的朋友的System.Guid類,因爲它會生成一個唯一的(當然,足夠的唯一的)128位號:

  • 生成新的GUID(System.Guid.NewGuid())
  • 商店該GUID某處(Application對象也許?)
  • 發送自定義URL在一封電子郵件,該GUID
  • 當用戶點擊該網站,讓他們進入你的電子郵件
  • 發送的密碼,如果密碼匹配,繼續前進,迫使他們進入一個新的密碼
+0

+1:感謝這個話題/邊信息:-) – 2012-10-08 14:06:53

+3

GUID應該是獨一無二的,但不應該是密碼強。可能猜測哪個GUID將被創建,從而爲特定帳戶創建一個令牌。 – Guillaume 2013-03-22 12:46:00

+0

@Guillaume,感謝您的信息,真的有可能嗎?你能解釋一下它是如何被猜測的嗎?我正在考慮使用GUID。 – Don 2014-10-15 07:32:20

59

也許最簡單的方法是將要修改的用戶表添加2個額外的c或者如果你不想修改現有的表,你可以添加一個名爲「UserPasswordReset」或類似的新的從屬表。列是這樣的:

PasswordResetToken UNIQUEIDENTIFIER, 
PasswordResetExpiration DATETIME 

如果使用附加表的路線走,你所能做的也增加了用戶ID列,使其成爲一個主鍵和一個foriegn重要的參考回到你的用戶表。還建議使用UNIQUE約束。然後,您只需在您的asp.net應用程序中使用Guid作爲標記。

流動可能是這樣的:

  1. 用戶請求密碼重置爲他們的帳戶
  2. 您插入表中的一個新的記錄(或更新他們的用戶記錄)由PasswordResetExpiration設定一個日期在未來(DateTime.Now.AddDays(1)),並將令牌設置爲Guid.NewGuid()
  3. 用查詢字符串中的guid向用戶發送鏈接到您的ResetPassword.aspx頁面(http://www.yoursite.com/ResetPassword.aspx?token=Guid-here
  4. 使用ResetPassword.aspx頁面進行驗證令牌和過期字段。 (I.E.確保DateTime.Now < PasswordResetExpiration)
  5. 提供一個簡單的表單,允許用戶重置此密碼。

我知道你想避免修改數據庫,但它確實可能是最簡單的方法。

+1

安全說明:UNIQUEIDENTIFIER並不意味着提供隨機性,並且在這種情況下不安全。基本上,你想要一個無法猜測的重置鏈接。爲了不可能猜到你的重置鏈接,你需要包含一個隨機數字,這個隨機數字由一個GUID不是的密碼安全的隨機數生成器生成。因此,除了2列以外,還需要第三個存儲該隨機數字作爲密碼,最後將重置鏈接中的GUID和密碼作爲參數發送出去。 – Gudradain 2015-07-20 19:57:13

2

我用一個散列類來創建由當前的日期/時間獨有的自動登錄和用戶的電子郵件地址:

string strNow = DateTime.Now.ToString(); 
string strHash = strNow + strEmail; 
strHash = Hash.GetHash(strHash, Hash.HashType.SHA1); 

得到哈希類:http://www.developerfusion.com/code/4601/create-hashes-md5-sha1-sha256-sha384-sha512/

然後只是把它從使用的網址:

if (Request.QueryString["hash"] != null) 
{ 
       //extract Hash from the URL 
       string strHash = Request.QueryString["hash"]; 
} 
+0

如何從哈希中重新獲取電子郵件地址和日期時間,以便您可以自動登錄?因爲哈希是單向的嗎?請教育。 – 2012-03-30 09:21:25

+0

@goths您可以將Hash值存儲在數據庫中,也可以發送包含URL的電子郵件,並附加用戶標識和散列。然後在URL指向的頁面上,將2與數據庫進行比較。這將是一個基本的解決方案,你需要一些更強大的東西來提高安全性。 – Alex 2012-04-06 23:36:18

+2

對不起,但我沒有看到實用程序發送散列編碼密鑰中的任何信息,如果要將它存儲在數據庫中的相同信息旁邊。唯一需要考慮的是唯一的密鑰,而不是任何「真實」信息的加密版本。 Goyuix提出的randow唯一生成的id(請參閱他的答案)是最好的選擇,如果您必須發送並存儲在數據庫中的某些內容才能夠在用戶單擊發送的電子郵件中的鏈接時找回它。 – 2012-10-08 14:10:35

2

@Alex

您也可以使用.NET中的System.Security.Cryptography類作爲散列算法。例如:

using System.Security.Cryptography; 
... 
var hash = SHA256CryptoServiceProvider.Create().ComputeHash(myTokenToHash); 
... 
0

向用戶電子郵件發送一些數據|字符串的目標是驗證帳戶所有者。請注意以下幾點:

  • 避免在重置或激活鏈接時發送重要信息。
  • 這是存儲唯一字符串數據連同用戶 帳戶並將其作爲該鏈接發送的最佳方式。但請注意,如果您只發送一個 部分作爲用戶電子郵件鏈接並在頁面中檢查它,則您的 應用程序可能會通過蠻力或字典 攻擊者處於危險之中。檢查一個字符串列表以查找一些鏈接 並更改密碼就足夠了。我知道這有一點機會,但不是零。

結果: 我認爲這是更好,如果你

  1. 結合用戶的電子郵件串鏈接,然後將它們加密 (不散列因爲散列值不能反轉),併發送至用戶 電子郵件。
  2. 用戶單擊並且您的頁面獲得加密值。
  3. 解密值。
  4. 提取用戶郵件。
  5. 在數據庫中查找電子郵件。
  6. 比較來自接收鏈接的字符串與附加到數據庫中的用戶 電子郵件的其他鏈接。

祝你好運。

1

我肯定會在這個過程中包含數據庫。一旦請求重置,最好指出帳戶被鎖定。

例如,如果您因爲認爲自己的帳戶可能已被泄密而更改了自己的密碼,那麼當您執行更改過程時,您絕對不希望它保持可訪問狀態。

另外,如果有人真的需要它並具有馬力,那麼在重置令牌中包含「真實」信息可以被解碼。生成一個隨機字符串會比較安全,將其保存在該用戶所在行的數據庫中,然後在單擊該鏈接時鍵入它。

這給了你兩件事情:

1)沒有什麼解密,因此價值沒有什麼可以從中獲得。 2)用戶記錄中存在令牌表示重置正在進行中,並應將帳戶視爲鎖定。

0

我會使用哈希碼來驗證密碼重置網址中的詳細信息。這一切都可以在不向DB寫入任何內容或向攻擊者發送任何特權信息的情況下完成。

簡要解釋正常的密碼salt和散列;說鹽是1111,密碼是password,你要連接這兩個字符串並且對字符串1111password進行散列,比如說這會給你一個散列9999,然後你會在你的用戶記錄中存儲原始鹽1111和散列9999

當您使用存儲鹽驗證密碼時,連接密碼嘗試,對其進行散列並與存儲的散列進行比較。例如asecret變爲1111asecret,但散列爲8888。這與原始散列不匹配,所以密碼匹配失敗。

當然鹽和哈希通常會正確地生成和計算與建立的加密庫(不要發明自己的!)。

對於密碼重置URL,我會爲用戶設置唯一標識符,例如電子郵件地址,請求的日期以及新的散列。這個哈希將從這些細節連接在一起加上已經爲用戶存儲的鹽和散列生成。

例如:

Email: [email protected] 
Request Date: 2014-07-17 
Salt: 1111 
Hash: 9999 

生成這些級聯的一個新的哈希值,即'[email protected]',說這給人的7777的哈希值。

的網址,然後我產生那麼將有電子郵件,請求日期和新的散列:

https:\\www.example.com\[email protected]&requestdate=2014-07-17&hash=7777 

服務器與它的鹽和散列將結合電子郵件和提供的日期,並確認它產生的散列與提供的相同。如果這是正確的,那麼它將顯示重置表單,隱藏在其後面的相同三個參數,否則會顯示錯誤。當輸入新密碼以防止該表單被欺騙時,它們會重新提交併重新檢查。

需要提供電子郵件地址才能發出請求,並且只能通過電子郵件發送到相同的地址。日期幾乎沒有特定的信息,哈希是不可逆的,所以什麼也不給。沒有數據寫入數據庫,任何篡改參數都會導致哈希失敗,並且URL會報告錯誤。

+1

這種方法存在問題。安全的哈希令令牌真的很長。要麼將鹽整合到散列本身(使其長約20個字符),要麼將此獨特鹽存儲在數據庫中。如果將salt存儲在數據庫中,那麼也可以存儲任何不存在於任何現有數據中的隨機令牌。 – martinstoeckli 2014-07-17 16:04:12

+0

@martinstoeckli因爲你已經在連接字符串中哈希了一個鹽,所以不需要添加另一個鹽。 OP確實要求它沒有存儲在數據庫中。 雖然你是對的,但網址很長,正確的散列會使它更長,但我希望鏈接被點擊或複製和粘貼,所以我不認爲這是一個問題太多。 – 2014-07-21 16:18:48

+0

我的意思是,鹽必須包含在鏈接可讀的形式,否則它是一個關鍵而不是鹽。鹽每個標記都是唯一的,這必須存儲在數據庫中,或者您可以從url中提取它。 – martinstoeckli 2014-07-21 20:14:22