Python存储和检索密码的最安全方法

35 投票
6 回答
62285 浏览
提问于 2025-04-15 21:11

我想把用户名和密码存储在数据库里,但不太确定最安全的方法是什么。我知道需要使用“盐”(salt),但不太清楚怎么安全地生成它,也不知道怎么用它来加密密码。如果能给点Python的示例代码就太好了。谢谢!

6 个回答

15

我在这里回答过这个问题:https://stackoverflow.com/a/18488878/1661689,@Koffie 也有回答。

我真的不知道该怎么强调,那个被接受的答案并不安全。虽然比直接用明文好,也比没有加盐的哈希值好,但它仍然非常容易受到字典攻击和暴力破解攻击。所以,请使用一个慢速的密钥派生函数,比如 bcrypt(或者至少用 PBKDF2,迭代次数设置为 10,000 次)。

16

我觉得最好使用一个专门用来加密密码的函数。这里有一些原因我会解释:https://stackoverflow.com/a/10948614/893857。现在,标准库里有一个专门用于加密密码的部分。里面甚至提到,你应该从一个安全的随机源获取盐值,比如用os.urandom()

42

把密码和盐值一起存成一个哈希值,并且单独存盐值。你可以看看Django是怎么做的:基本文档源代码。 在数据库里,他们把内容存成一个字符字段,格式是 <哈希类型>$<盐值>$<哈希值>。你也可以把这三部分分别存到不同的字段里。

设置密码的函数:

def set_password(self, raw_password):
    import random
    algo = 'sha1'
    salt = get_hexdigest(algo, str(random.random()), str(random.random()))[:5]
    hsh = get_hexdigest(algo, salt, raw_password)
    self.password = '%s$%s$%s' % (algo, salt, hsh)

get_hexdigest 只是一些哈希算法的简单封装。你可以用 hashlib 来实现。比如可以这样写:hashlib.sha1('%s%s' % (salt, hash)).hexdigest()

检查密码的函数:

def check_password(raw_password, enc_password):
    """
    Returns a boolean of whether the raw_password was correct. Handles
    encryption formats behind the scenes.
    """
    algo, salt, hsh = enc_password.split('$')
    return hsh == get_hexdigest(algo, salt, raw_password)

撰写回答