4

我使用 mitsuhiko 的 pbkdf2 实现进行密码散列:

def pbkdf2_bin(data, salt, iterations=1000, keylen=24, hashfunc=None):
    """Returns a binary digest for the PBKDF2 hash algorithm of `data`
    with the given `salt`.  It iterates `iterations` time and produces a
    key of `keylen` bytes.  By default SHA-1 is used as hash function,
    a different hashlib `hashfunc` can be provided.
    """
    hashfunc = hashfunc or hashlib.sha1
    mac = hmac.new(data, None, hashfunc)
    def _pseudorandom(x, mac=mac):
        h = mac.copy()
        h.update(x)
        return map(ord, h.digest())
    buf = []
    for block in xrange(1, -(-keylen // mac.digest_size) + 1):
        rv = u = _pseudorandom(salt + _pack_int(block))
        for i in xrange(iterations - 1):
            u = _pseudorandom(''.join(map(chr, u)))
            rv = starmap(xor, izip(rv, u))
        buf.extend(rv)
    return ''.join(map(chr, buf))[:keylen]

此函数返回二进制摘要,然后将其编码为 base64 并保存到数据库。此外,当用户登录时,该 base64 字符串被设置为 cookie。

此函数用于密码哈希比较:

def comparePasswords(password1, password2):
    if len(password1) != len(password2):
        return False
    diff = 0
    for x, y in izip(password1, password2):
        diff |= ord(x) ^ ord(y)
    return diff == 0

我想知道二进制哈希和base64字符串在安全性方面的比较是否有任何区别?例如,当用户登录时,我计算提交密码的二进制摘要,从数据库中解码 base64 字符串,然后比较两个二进制哈希,但如果用户有一个带有 base64 字符串的 cookie,我直接将它与来自的字符串进行比较数据库。

第二个问题是关于盐的:

os.urandom 返回二进制字符串,但在它用于哈希生成之前,我还将它编码为 base64。有什么理由我不应该这样做并以二进制形式使用盐吗?

4

1 回答 1

10

回答问题 1:比较字节与比较 base64 编码字符串时没有重大的安全差异......您只是在比较nn*4/3元素。使用 base64的运行时间会4/3更长,但时间量仍然微不足道:)

也就是说,有一个 python 开发人员讨论了类似的“恒定时间”比较函数,他们遇到了一些 VM 级别的陷阱——如果你的输入是unicode字符串而不是bytes,特别是如果 unicode 包含非 ASCII 字符,可能仍然存在一些微妙的定时攻击(比短路相等攻击小几个数量级)。因此,如果可能的话,我会坚持使用字节(无论是二进制数据还是 ASCII 编码的 base64 数据)。但是,在 PBKDF2 的情况下,我不会太担心,因为比较函数旨在击败的定时攻击更多地适用于 HMAC 签名,而不是密码哈希验证......但安全总比抱歉好。

回答问题 2:对于不安全的结构,例如md5(salt+password),首先对 salt 进行编码将允许攻击者使用现有的 ASCII md5 表来攻击整个摘要,而原始二进制 salt 会使此类表无用。然而,PBKDF2-HMAC 做了足够多的修改,唯一重要的是盐包含n一些熵——无论是n/8原始字节的形式,还是n/6base64 字符的形式都不会影响安全性。

其他说明:我只是想添加与您发布的内容有关的其他几点...

  1. 出于安全考虑,我强烈建议使用 SHA256/512 而不是 SHA1 作为 PBKDF2-HMAC 散列函数,并且为了安全起见 >= 10,000 轮(截至 2012 年)。

  2. 在 cookie 中发送摘要(即使没有盐)的想法让我觉得可能不安全......如果有人窃取了该 cookie(例如跨站点脚本攻击),他们可能会以用户身份登录(尽管我不知道其余的应用程序的安全设置)。使用带有随机生成的会话 id 的会话层(例如Beaker)可能是一个不错的选择。

  3. 我建议使用 Passlib PBKDF2consteq实现,它的 PBKDF2 例程比 mitsuhiko 快 5 倍,并且可以利用M2Crypto(如果存在)。(免责声明:我是 Passlib 的作者)。它还有一个现成的pbkdf2-sha256密码散列函数,但如果你在 cookie 中发送摘要,它就没有多大用处了。

于 2012-08-06T17:01:08.730 回答