12

和我一起对抗弱密码哈希。

PBKDF2 密码散列应该包含盐、迭代次数和散列本身,以便以后验证。PBKDF2 密码哈希是否有标准格式,例如 RFC2307 的 {SSHA}?BCRYPT 很棒,但 PBKDF2 更容易实现。

显然,没有规格。所以这是我的规格。

>>> from base64 import urlsafe_b64encode
>>> password = u"hashy the \N{SNOWMAN}"
>>> salt = urlsafe_b64decode('s8MHhEQ78sM=')
>>> encoded = pbkdf2_hash(password, salt=salt)
>>> encoded
'{PBKDF2}1000$s8MHhEQ78sM=$hcKhCiW13OVhmLrbagdY-RwJvkA='

更新:http ://www.dlitz.net/software/python-pbkdf2/定义了一个crypt()替代品。我更新了我的小规格以匹配他的,除了他的开头$p5k2$不是{PBKDF2}. (我需要从其他 LDAP 样式 {SCHEMES} 迁移)。

也就是说{PBKDF2},小写十六进制的迭代次数,$编码的urlsafe_base64盐,$以及urlsafe_base64编码的 PBKDF2 输出。salt 应该是 64 位,迭代次数至少应该是 1000 次,带有 HMAC-SHA1 输出的 PBKDF2 可以是任意长度。在我的实现中,默认情况下它总是 20 个字节(SHA-1 哈希的长度)。

密码在通过 PBKDF2 发送之前必须编码为 utf-8。没有关于它是否应该被规范化为 Unicode 的 NFC 的消息。

这种方案的iterations暴力破解成本应该比 {SSHA} 高几倍。

4

2 回答 2

4

PBKDF2 的参数(盐和迭代)有一个规范,但它不包括哈希。这包含在PKCS #5 版本 2.0中(参见附录 A.2)。一些平台内置了对这种 ASN.1 结构的编码和解码的支持。

由于 PBKDF2 确实是一个密钥派生函数,因此指定一种将“哈希”(这是真正的派生密钥)与派生参数捆绑在一起的方法是没有意义的——在正常使用中,密钥必须保留秘密,并且永远不会被存储。

但是对于用作单向密码散列,散列可以存储在带有参数的记录中,但在它自己的字段中。

于 2009-09-24T18:34:21.000 回答
4

我会和你一起对抗弱哈希。

OWASP 有一个密码存储备忘单(https://www.owasp.org/index.php/Password_Storage_Cheat_Sheet)和一些指导;他们建议截至 2012 年至少进行 64,000 次 PBKDF2 迭代,每两年翻一番(即 2012 年为 90,510 次)。

请注意,为每个用户 ID 存储一个长的、加密的随机盐始终是基本的。

请注意,每个用户 ID 的迭代次数变化很大,并将迭代次数与 salt 一起存储会增加破解软件的复杂性,并可能有助于排除某些优化。例如,“bob”使用 135817 次迭代进行加密,而“alice”使用 95,121 次迭代,即 2013 年可能至少为 (90510 + RAND(90510))。

另请注意,如果允许用户选择“password”、“Password1!”、“P@$$w0rd”和“P@$$w0rd123”等弱密码,所有这些都是无用的,所有这些都将被基于规则的字典攻击确实非常快(后者只是具有以下规则的“密码”:大写首字母,1337-speak,在末尾添加一个三位数)。拿一个基本的字典列表(phpbb,一个好的,小的初学者词表)并应用这样的规则,你会破解很多人们尝试“聪明”技巧的密码。

因此,在检查新密码时,不要只使用“大写、小写、数字、数字全部四个,至少11个字符长”,因为“P@$$w0rd123”符合这个看似非常严格的规则。相反,使用该基本字典列表并查看基本规则是否会破解它(这比实际尝试破解要简单得多 - 您可以将您的列表及其单词小写,然后简单地编写类似“如果最后 4 个字符是一个共同的年份,检查除了最后四个字符之外的所有字符”,以及“如果最后 3 个字符是数字,则检查除最后​​ 3 个字符之外的所有字符”和“检查除最后​​两个字符之外的所有字符”和“De-1337 密码 - 将 @ 转换为 a,将 3 转换为 e,依此类推,

就密码而言,一般来说是一个好主意,特别是如果在单词中间添加了一些其他字符,但当且仅当它们足够长时,因为你放弃了很多可能的组合。

请注意,即使在 2012 年,具有 GPU 的现代机器每秒也有数百亿次哈希迭代(MD5、SHA1、SHA-256、SHA-512 等)。就单词组合“正确的马电池主食”而言输入密码,这个充其量是一个非常普通的密码——它只有 4 个长度为 7 或更少的全小写英文单词,带有空格。因此,如果我们去寻找具有 180 亿次猜测的 XKCD 样式密码,则进行第二次设置: 现代小型美国英语词典有: 6k 个长度为 5 或更少的词 21k 个长度为 7 或更少的词 36k 个长度为 9 或更少的词 46k 个词长度为 11 或更少的 49k 个长度为 13 或更少的字

使用 XKCD 风格的密码短语,无需费心按受欢迎程度过滤单词(“正确”、“椅子”、“笨蛋”、“出血”),我们有 21k^4,这只有大约 2E17 种可能性。使用 180 亿/秒的设置(如果我们面临单次 SHA1 迭代,一台机器有 8 个 GPU),大约需要 4 个月来彻底搜索键空间。如果我们有十个这样的设置,那就是大约两周。如果我们排除像“dumpier”这样不太可能的词,那么快速第一次通过会快得多。

现在,如果你从“巨大”的 linux 美式英语单词表中找到单词,例如“Balsamina”或“Calvinistically”(都使用“转到行”功能选择“,那么我们将有 30k 个长度为 5 或少于 115k 个长度为 7 或更少的词 231k 个长度为 9 或更少的词 317k 个长度为 11 或更少的词 362k 个长度为 13 或更少的词

即使有 7 个最大长度限制,以这个庞大的字典为基础并随机选择单词,我们有 115k^4 ~= 1.8E20 种可能性,如果设置保持最新,则大约需要 12 年(每 18 个月功率翻一番)。这与 13 个字符、小写字母 + 仅数字的密码极为相似。大多数估计会告诉你“300 年”,但他们没有考虑摩尔定律。

于 2013-01-02T16:30:30.953 回答