2010-01-09 149 views
16

我創建一個PHP的網站,該網站包括用戶註冊,和我想知道的「確認電子郵件」代碼的最佳做法。通過生成代碼,並在一封電子郵件中,他可以再使用,以激活其賬戶將其發送到用戶我做到這一點 -最佳做法電子郵件確認代碼

新用戶必須確認他們的電子郵件地址。而不是存儲在數據庫中這一關鍵,我使用一個方便的小解決辦法:代碼的結果是:

md5("xxxxxxxxx".$username."xxxxxxxxxxx".$timestamp."xxxxxxxxx"); 

其中$時間戳是指用戶創建時間。總的來說,我對此很滿意,但後來我開始想,這足夠安全嗎?那碰撞的可能性呢?我還需要生成密碼重置代碼等。如果我使用了類似的方法,碰撞可能會導致一個用戶無意中重置另一個用戶的密碼。這並不好。

那麼,你如何做這些事情?我的想法是以下格式的表:

codePK (int, a-I), userID (int), type (int), code (varchar 32), date (timestamp) 

其中「類型」是1,2或3,意思是「激活」,「電子郵件變」或「密碼重置」。這是做這件事的好方法嗎?你有更好的方法嗎?

使用類似上述的方法,可能我會自動刪除任何超過兩天老不使用的cron的作業?我的主機(almostfreespeech.net)不支持它們。如果可能的話,我想避免在外部主機上執行cron-job,而wget是一個刪除內容的腳本,因爲這只是messy = P。

謝謝!
麻辣

更新:
爲了澄清:我已經意識到可靠而安全地去了解這個任務的唯一方法是使用一個數據庫,這是原函數試圖避免。我的問題是如何構建表(或多個表)。有人建議我不要使用codePK,只需將代碼設爲PK即可。所以總之,我的問題是:這是你做的?

+0

電子郵件確認代碼的最佳做法?讓他們離開... – Leo 2010-01-09 13:52:20

+1

用戶在文件上有一個有效的電子郵件地址是很重要的,如果僅用於密碼重置。雖然人們可以聲稱「這是用戶的責任」,但這是我們正在處理的真實世界......只要第一個「永遠不會忘記密碼」的人忘記密碼,大概一到兩週後,我的系統將是「最愚蠢的」。 – Mala 2010-01-10 12:49:30

回答

10

當我需要這些類型的招數是正常的兩個原因之一,無論你提到:

  1. 作爲用於發送到用戶
  2. 作爲用於密鑰驗證電子郵件的關鍵密碼重置鏈接

當然,還有許多其他場合你會考慮使用這種結構。

首先,你應該總是使用某種隱藏的鹽,只有你知道。請注意,這個鹽對每個用戶應該是不同的。鹽可以例如計算爲sha256(something random)。然後將該鹽與用戶名和密碼一起存儲在數據庫中(用鹽進行散列)。

發送密碼重置鏈接時我會做的是創建另一個鹽(不要讓用戶訪問任何用你的鹽散列的東西,他知道他的密碼,所以使用暴力,他可能會找出你的鹽) 。另一種鹽,實際上只是一個隨機字符串的散列(你可能想在這裏找到md5,正如你提到的那樣,長度是一個問題),你應該保存到數據庫中。

通常情況下,您可以避免在用戶表中添加額外的列。但是,這也存在一些問題,主要是一旦密碼被重置或用戶被激活,您將從數據庫中刪除密鑰,導致大多數行具有空值,這反過來又帶來一些其他麻煩。

這本質歸結爲:採用了獨特的換的用戶鹽(也許是一個全球性的,祕密的鹽)

  • 哈希用戶的密碼。
  • 通過散列一些隨機或僞隨機來源(如時間戳,mt_rand()甚至random.org)來生成密鑰,如果您真的想要隨機的東西。
  • 切勿使用全局鹽,或者是對用戶唯一的散列任何用戶獲得訪問權限,包括密碼重置鍵,啓動鍵等

請不說我怎麼也不鹽意味着安全專家,我可能已經忘記了很多事情,而且我可能提到了一些非常糟糕的做法。只是我的5美分;-)

1

這是足夠安全的權利,直到在那裏你發佈你在互聯網上法點!這是因爲你依靠默默無聞的安全,這不是一個好主意。

你應該使用某種加密散列函數或MAC理想,其中包含只認識你一個祕密密鑰。

+2

顯然這個'x'實際上並不是代碼中的'x' – Mala 2010-01-09 12:30:04

+0

在這種情況下,你已經創建了一個密鑰散列函數,你很好。我應該可能已經猜到了......;) – 2010-01-09 12:40:40

+0

;)對不起,我以爲我已經指定 - 但顯然我編輯的位,我明確表示,在任何情況下,我想知道如果表結構/使用所有代碼的單個表是合適的 – Mala 2010-01-09 12:56:42

0

爲什麼不讓代碼字段唯一索引?所以永遠不會有共謀?

另外,如果你不需要來自用戶的輸入創建的哈希和它匹配的數據庫散列(電子郵件確認,密碼重置等) - 你可以隨機字符串添加到哈希身上,就像 md5('xxx'.$username.'xxx'.time().'xxx'.rand())

+0

那麼我不能在沒有使用數據庫的情況下檢查它 - 該函數的全部要點是避免使用它們。如果我打算使用數據庫,那麼我可以讓整個字符串完全是隨機的 – Mala 2010-01-09 12:36:21

2

爲什麼使用任何用戶的數據作爲授權密鑰的基礎?

我認爲你正在存儲數據庫中的去激​​活數據,爲什麼不只是添加一個簡單的隨機密鑰的額外記錄(也許是一些額外的操作md5'ed uniqid),然後檢查呢?

+0

原來我試圖避免必須使用數據庫 - 因此使用userdata – Mala 2010-01-09 12:35:24

+1

說實話,我不能幫助,但認爲數據庫是要走的路,否則你將哈希/操縱一個相當有限的靜態數據池。 – 2010-01-09 12:39:37

0

爲什麼不要求用戶輸入他們的用戶名他們的代碼,從而消除碰撞的任何問題?你不會因爲安全問題而失去任何東西,因爲你仍然在要求他們從電子郵件中獲得的鑰匙,但是你會阻止他們重置其他用戶的密碼。

+1

理想情況下,他們只需點擊電子郵件中的鏈接即可。我不希望這太可怕了= P – Mala 2010-01-09 12:36:56