2009-06-03 159 views
30

我正在使用Mysql,並且我認爲最好將用戶個人信息及其登錄名和密碼分隔成兩個不同的表,然後在兩個表之間引用它們。如何最好地存儲用戶信息和用戶登錄名和密碼

注意:爲了澄清我的文章,我瞭解保護密碼(散列,鹽等)的技術。我只知道,如果我遵循我生活中其他部分的實踐(投資,數據備份,甚至是個人存儲),在最壞的情況下(包括表或火),信息在表格之間分裂,可以保護您的額外的數據。

+0

只是爲了澄清;你想知道如何正確地在數據庫中存儲密碼,或者你是否想知道用戶配置文件數據是否應與基礎數據分開?我爲前者回答,但重讀這個問題時,你似乎想要後者。 – Rob 2009-06-03 23:09:56

+1

大多數答案都關注散列和醃製密碼的方法。這是值得的信息,但沒有解決OP的問題。 – 2009-06-03 23:20:55

+0

是的,我將使用sha1和salting來存儲密碼。 – Tim 2009-06-04 12:47:27

回答

35

不要存儲密碼。如果它坐在磁盤上,它可能會被盜。相反,存儲密碼散列。 Use the right hashing algorithm,就像bcrypt(其中包含一個鹽)。

編輯:OP已回覆他了解上述問題。

沒有必要將密碼存儲在與登錄信息不同的表中。如果一個數據庫表被破壞,那麼訪問同一數據庫中的另一個表並不是一個大的飛躍。

如果您充分關注安全性和安全性,可以考慮將用戶憑據存儲在與域數據完全分離的數據存儲中。通常做的一種方法是將憑證存儲在LDAP目錄服務器中。這也可能有助於您稍後進行的任何單點登錄工作。

14

將它們放在同一張表中沒有任何問題。事實上,它會更快,所以我強烈推薦它。我不知道你爲什麼想分裂它。

+1

我嚴重懷疑它會更快,因爲檢查名稱/密碼和userdata將在任何應用程序的非常不同的部分,並在非常不同的時刻完成。想想:你需要每次登錄拒絕的有效數據嗎?在您接受後,您是否每次閱讀個人資料時都需要檢查密碼? 當然,我通常不打擾,把它放在一起。但這只是爲了簡單,而不是表現。 – Javier 2009-06-03 22:43:02

+2

不,因爲每當你獲得用戶數據時你都需要加入JOIN。無論是那樣的還是你都會有很多重複的信息(例如,用戶名和ID都存儲在這兩個中)等,這兩者都不是最優的。無論哪種方式,沒有理由將其分成兩個不同的表格;無論是出於性能還是簡單性,它都沒有任何意義。 – 2009-06-03 23:02:22

+1

+1這是回答OP問題的唯一答案(迄今爲止)。 – 2009-06-03 23:18:01

0

您應該將它們存儲在同一個表中,並使用單向加密。 MD5可以工作,但很弱,所以你可能會考慮像SHA1或其他方法。將2個項目存儲在單獨的表格中沒有任何好處。

7

我會嘗試回答你原來的問題。除非你有很多個人信息要收集,否則將它全部放在一張桌子上是沒問題的。在這種情況下,分解它可能是有意義的。應根據您處理的個人信息數量以及需要訪問的頻率做出該決定。

我想說的大部分時間我會做這樣的事情在一個表:

UserID, FirstName, LastName, Email, Password, TempPassword 

但是......如果你收集遠不止這些。假設你正在收集電話,傳真,出生日期,傳記等等。如果大多數信息很少被訪問,那麼我可能會把它放在自己的表中,並將它與一對一的關係聯繫起來。畢竟,您在一張桌子上擁有的列數越少,對這張桌子的查詢就越快。有時候簡化最常訪問的表格是有意義的。雖然每當您需要訪問個人信息時,JOIN的性能都會受到影響,所以您必須考慮這一點。

編輯 - 你知道嗎,我只是想到了一些東西。如果您在用戶名或電子郵件字段中創建索引(無論您希望如何),它幾乎可以完全消除在用戶表中創建太多列的性能缺陷。我說,因爲無論何時登錄WHERE子句,如果它有一個索引,實際上會非常快速地找到用戶名,如果該表中有100列,則無關緊要。 所以我改變了我的看法。我把它放在一張桌子上。;)

無論哪種情況,由於安全似乎是一個熱門話題,密碼應該是一個散列值。我建議SHA1(或SHA256,如果你真的關心它)。 TempPassword也應該使用散列,並且它只存在於忘記的密碼功能。很顯然,用散列表不能解密並向用戶發送其原始密碼。因此,您可以生成一個可以登錄的臨時密碼,然後強制他們在登錄後再次更改密碼。

3

首先,說明(希望)顯而易見的,如果你可以以任何方式避免存儲用戶名和密碼,這是一項重大責任,如果您的憑證存儲被違反,它可能爲同一用戶提供對許多其他地方的訪問(由於密碼共享)。

如果必須存儲憑據:

  • 不要存放可逆的形式;使用SHA-256等公認的算法存儲散列。使用來自信譽良好的可靠來源的加密軟件 - 不要試圖自己滾動,你可能會弄錯它。
  • 對於每個憑證集,存儲salt以及散列數據;這用於「填充」散列,以便兩個相同的密碼不會產生相同的散列 - 因爲這會泄露密碼相同。
  • 使用安全的隨機生成器。弱隨機性是加密相關安全失敗的首要原因,而不是密碼算法。

如果您必須存儲可逆憑據:

  • 選擇一個好的加密算法 - AES-256,3DES(日期),或公共密鑰密碼。使用來自信譽良好的可靠來源的加密軟件 - 不要試圖自己滾動,你可能會弄錯它。
  • 對於每個證書集,存儲salt(未加密)以及加密的數據;這用於「加密」加密密碼,使得兩個相同的密碼不會產生相同的密文 - 因爲這會泄露密碼相同。
  • 使用安全的隨機生成器。弱隨機性是加密相關安全失敗的首要原因,而不是密碼算法。
  • 將加密/解密密鑰與您的數據庫分開存儲在O/S安全文件中,只能訪問您的應用程序運行時配置文件。這樣,如果您的數據庫被破壞(例如通過SQL注入),您的密鑰不會自動受到攻擊,因爲這需要訪問硬盤。如果您的O/S支持與配置文件綁定的文件加密,請使用它 - 它只能提供幫助,而且通常是透明的(例如NTFS加密)。
  • 如果可行,請使用主密碼來存儲自己加密的密鑰。這通常意味着你的應用。在啓動時需要輸入密碼 - 從腳本的參數中提供密碼是沒有用的,因爲如果你的硬盤被破壞了,你必須假定密鑰文件和腳本都可以被查看。
  • 如果用戶名不必定位帳戶記錄,則同時加密用戶名和密碼。
17

密碼應存儲爲加密哈希,這是一種不可逆操作,可防止讀取純文本。在對用戶進行身份驗證時,密碼輸入會受到相同的哈希處理和哈希值的比較。

避免使用諸如MD5或SHA1之類的快速便宜的散列;目標是讓攻擊者計算彩虹表(基於散列衝突)的代價高昂;一個快速哈希抵消這一點。使用昂貴的散列對於驗證場景來說不是問題,因爲它對散列的單次運行沒有影響。

除了散列之外,還可以用散列值隨機生成一個值;一個隨機數,然後存儲在數據庫中並在散列之前與數據串聯。這增加了計算衝突時必須生成的可能組合的數量,並因此增加了生成彩虹表的總體時間複雜度。

您的密碼哈希列可以是固定長度;您的加密散列應該輸出可以編碼爲固定長度的值,對於所有散列而言,這些值是相同的。

儘可能避免滾動自己的密碼認證機制;使用現有解決方案,如bcrypt

有關如何處理密碼以及需要關注的問題的詳細說明,請參見http://www.matasano.com/log/958/enough-with-the-rainbow-tables-what-you-need-to-know-about-secure-password-schemes

作爲最後一點,請記住,如果攻擊者獲得對數據庫的訪問權限,那麼您的直接關注應該可能與他們可能訪問的任何敏感或個人身份信息以及可能造成的任何損害相關。

2

根據我個人的經驗,將個人信息和登錄信息存儲在個人數據庫中是最佳實踐。原因是應該發生SQL注入,它是有限的(除非入侵者知道你的數據庫的內部佈局)到數據所屬的表,而不是提供對整個數據集的訪問。

但是,請注意,這可能是以犧牲需要執行更多查詢爲代價的,因此性能受到影響。

2

所有這些數據是否總是與用戶有1:1的關係?如果您可以預先允許用戶擁有多個地址,電話號碼等,那麼您可能需要將個人信息分解到單獨的表格中。

相關問題