2009-03-05 59 views
75

在數據庫(最好是SQL Server 2005)中存儲密碼的首選方法/數據類型是什麼。在我們的幾個應用程序中,我一直在使用.NET加密庫,然後將它們作爲二進制文件存儲在數據庫中(16)。這是首選的方法,或者我應該使用不同的數據類型還是分配比16更多的空間?在數據庫中存儲密碼的首選方法

+1

我有一種感覺,這可能是一個傻瓜,但我覺得可能是一個欺騙的它竟然是關於實際的數據庫登錄,而不僅僅是存儲應用程序/網站登錄。 – TheTXI 2009-03-05 17:16:56

+1

您能否澄清一下您的問題,以解釋您是使用「加密」還是「哈希」功能?我認爲你的意思是後者,但差異非常顯着。 – ine 2009-03-05 18:28:33

回答

80

我存儲鹽漬哈希相當於數據庫的密碼永不密碼本身,則總是散列比較什麼樣的用戶在通過生成一個。

這太危險了有史以來存儲字面密碼數據隨處可見這使得恢復成爲不可能,但是當有人忘記或丟失密碼時,您可以運行一些檢查並創建一個新密碼。

+0

@昆頓:這就是我所做的。使用.net加密庫,它將散列密碼,然後將其傳遞到數據庫並作爲二進制文件存儲。我只能通過散列用戶輸入並將其與存儲的內容進行比較來比較密碼。 – TheTXI 2009-03-05 17:14:02

+0

這聽起來像是你在正確的軌道上。 – 2009-03-05 17:15:24

+1

如果您使用java,我推薦jbcrypt。極其簡單易用 – 2009-03-05 18:13:38

15

我做了同樣的事情,你已經描述過,除了它被存儲爲一個字符串。我Base64編碼加密的二進制值。分配的空間量取決於加密算法/密碼強度。

我認爲你做得對(假設你使用的是Salt)。

+2

+1用於解決這裏的真實問題。 – erickson 2009-03-05 17:29:21

46

首選方法:從不在數據庫中存儲密碼。只有它的哈希。加鹽調味。

8

由於散列函數的結果是一系列範圍爲0到255(或-128到127,取決於您的8位數據類型的有符號性)的字節,因此將其存儲爲原始二進制字段是最有意義的,因爲它是最緊湊的表示形式,不需要額外的編碼和解碼步驟。

某些數據庫或驅動程序對二進制數據類型沒有很好的支持,或者有時候開發人員對它們感覺不太舒服。在這種情況下,使用像Base-64或Base-85這樣的二進制到文本編碼,並將結果文本存儲在字符字段中是可以接受的。

所需字段的大小由您使用的散列函數決定。 MD5總是輸出16個字節,SHA-1總是輸出20個字節。一旦你選擇了一個散列函數,你通常會堅持下去,因爲改變需要重置所有現有的密碼。所以,使用可變大小的字段不會爲你購買任何東西。


關於 「最佳」 的方式來進行散列,我試着向其他有關該主題的SO問題提供很多答案:

8
  1. 商店的鹽析密碼的哈希,如bcrypt(nounce + PWD)。您可能更喜歡對SHA1或MD5進行加密,因爲它可以調整爲CPU密集型,因此可以使暴力攻擊的方式變得更長。
  2. 在幾次登錄錯誤後添加驗證碼(以避免暴力攻擊)
  3. 如果您的應用程序有一個「忘記了我的密碼」鏈接,請確保它沒有通過電子郵件發送新密碼,而是應該發送一個鏈接到一個(安全)頁面,允許用戶定義一個新的密碼(可能只有在確認了某些個人信息後,例如用戶的出生日期)。另外,如果您的應用程序允許用戶定義新密碼,請確保您要求用戶確認當前密碼。

    1. =>離線字典攻擊:
    2. ,顯然,安全登錄表單(通常使用HTTPS)和服務器本身

    通過這些措施,您的用戶密碼將被很好地對付保護

  4. =>活字典攻擊
  5. =>拒絕服務攻擊
  6. =>各種各樣的攻擊!
2

如果您使用的是ASP.Net,則可以使用內置成員資格API。

它支持多種類型的存儲選項,包括:單向散列,雙向加密,md5 +鹽。 http://www.asp.net/learn/security欲瞭解更多信息。

如果你不需要任何太花哨的東西,這對於網站來說很棒。

如果不使用這裏是ASP.Net從4guys到幾篇文章一個很好的鏈接,並在CodeProject

http://aspnet.4guysfromrolla.com/articles/081705-1.aspx http://aspnet.4guysfromrolla.com/articles/103002-1.aspx http://www.codeproject.com/KB/security/SimpleEncryption.aspx

4

我使用的用戶名的SHA散列,在一個GUID web配置和密碼,並以varchar(40)的形式存儲。如果他們想要蠻力/字典,他們也需要針對guid攻擊Web服務器。如果用戶找到密碼,用戶名會在整個數據庫中創建一個彩虹表。如果用戶想要更改他們的用戶名,我只需要同時重置密碼。

System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(
    username.ToLower().Trim(), 
    ConfigurationManager.AppSettings("salt"), 
    password 
); 
3

您可以在您的數據庫中使用多個哈希,它只需要一點額外的努力。如果您認爲將來有可能需要支持其他格式,那麼這是非常值得的。我常會用到的密碼條目像

{hashId} $ {鹽} $ {散列密碼}

其中「hashId」只是一些數字我用內部認識到,例如,我使用SHA1具有特定的哈希模式; 「鹽」是鹼基64編碼的隨機鹽;和「散列密碼」是一個base64編碼的散列。如果你需要遷移哈希值,你可以截取舊密碼格式的人,並在下次登錄時讓他們更改密碼。

正如其他人提到的,你要小心你的哈希值,因爲它很容易做一些事情這不是很安全,例如,H(鹽,密碼)遠比H(密碼,鹽)弱,但同時你想要平衡與網站內容價值相關的努力。我會經常使用H(H(密碼,鹽),密碼)。

最後,與使用各種期望文本數據的工具相比,使用base64編碼密碼的成本適中。是的,他們應該更加靈活,但是你是否準備好告訴你的老闆他不能使用他最喜歡的第三方工具,因爲你想每個記錄保存幾個字節? :-)

編輯添加一個其他的評論:如果我建議故意使用一種算法,即使是十分之一秒鐘散列每個密碼,我都會很幸運,只能從我老闆的辦公室裏笑出來。 (不太幸運?他會在我的下一次年度審查中記下一些事情來討論。)當你有幾十甚至幾百個用戶時,焚燒那個時間並不是問題。如果你推動10萬用戶,你通常會同時登錄多個人。你需要快速而堅強的東西,而不是緩慢而堅強。 「但是信用卡信息怎麼樣?」由於存儲的信用卡信息不應該位於常規數據庫附近,並且無論如何都會被應用程序加密,而不是個人用戶,所以最多是不誠實的。

2

由於你的問題是關於存儲方法&大小,我會解決這個問題。

存儲類型可以是二進制或文本表示(base64是最常見的)。二進制文件較小,但我覺得使用文本更容易。如果你正在做每個用戶salting(每個密碼不同的salt),那麼將salt + hash存儲爲單個組合字符串會更容易。

大小取決於散列算法。 MD5的輸出總是16個字節,SHA1總是20個字節。 SHA-256 & SHA-512分別是64個字節。如果您使用的是文本編碼,則根據編碼方法的不同,您需要的存儲空間稍多一些。我傾向於使用Base64,因爲存儲相對便宜。 Base64將需要大約33%的領域。

如果你有每個用戶salting你也需要空間的散列。把它放在一起64位salt + SHA1哈希(160位)base64編碼需要40個字符,所以我把它存儲爲char(40)。

最後,如果你想做正確的事情,你不應該使用單一的散列,而是像RBKDF2這樣的密鑰派生函數。 SHA1和MD5哈希速度非常快。即使是單線程應用程序也可以在四核機器上每秒散列大約30K到50K個密碼,每秒鐘密碼達到200K個密碼。 GPU可以將每秒鐘的密碼從100倍提高到1000倍。有了這種速度,蠻力攻擊就成爲一種可接受的入侵方法。 RBKDF2允許你指定迭代次數來微調你的哈希是多麼「緩慢」。重點不在於讓系統癱瘓,而是要挑選一些迭代,以便限制哈希吞吐量的上限(例如每秒500次哈希)。未來的證明方法將包括密碼字段中的迭代次數(迭代+鹽+散列)。這將允許未來增加迭代以跟上更強大的處理器。爲了更靈活地使用varchar來允許未來可能的更大/替代哈希。

在.NET實現RFC2892DeriveBytes http://msdn.microsoft.com/en-us/library/system.security.cryptography.rfc2898derivebytes.aspx

相關問題