34

希望将用户名和密码存储在数据库中,并且想知道最安全的方法是什么。我知道我必须在某处使用盐,但不确定如何安全地生成它或如何应用它来加密密码。一些示例 Python 代码将不胜感激。谢谢。

4

6 回答 6

41

将密码+盐存储为哈希和盐。看看 Django 是如何做到的:基本文档源代码。在数据库中,它们存储 <type of hash>$<salt>$<hash>在单个字符字段中。您还可以将这三个部分存储在单独的字段中。

设置密码的功能:

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)
于 2010-04-03T17:50:07.483 回答
16

我认为最好为此使用专门用于散列密码的函数。我在这里解释了一些原因:https ://stackoverflow.com/a/10948614/893857 现在标准库在文档中有一个专门的部分用于散列密码。它甚至提到您应该从加密安全的随机源(例如os.urandom().

于 2012-06-08T12:22:37.583 回答
15

我在这里回答了这个问题:https : //stackoverflow.com/a/18488878/1661689,@Koffie 也是如此。

我不知道如何强调接受的答案并不安全。它比纯文本好,比无盐哈希好,但它仍然极易受到字典甚至暴力攻击。相反,请使用像 bcrypt 这样的慢速 KDF(或至少10,000 次迭代的 PBKDF2)

于 2013-08-28T17:42:49.447 回答
3

如果您对应用程序的两个端点都有足够的控制权,那么绝对最好的方法是使用PAK-Z+

(已编辑:原版推荐SRP,但 PAK-Z+ 有安全证明。)

于 2010-04-07T10:46:24.427 回答
2

对于烧瓶应用程序或任何 python 应用程序,您可以使用 werkzeug WSGI Web 应用程序库,它为您提供了使用盐和不同类型的算法以如下格式生成和解码密码的选项:method$salt$hash

默认盐长度为 16,使用的算法为 sha256

例如。

from werkzeug.security import generate_password_hash, check_password_hash

raw_pwd = 'mySecurePassword'

# genreates the encrypted password
hashed_pwd = generate_password_hash(raw_pwd)

# to verify the password
print(check_password_hash(hashed_pwd, raw_pwd)) # return boolean value after validating password

您可以在此处阅读有关 werkzeug 安全性的更多信息:https ://werkzeug.palletsprojects.com/en/2.0.x/utils/#module-werkzeug.security

于 2021-09-01T05:32:45.870 回答
0

这是一种更简单的方法(取自 effbot),前提是长度大于 8 的密码不会有问题*:

import crypt

import random, string

def getsalt(chars = string.letters + string.digits):
    # generate a random 2-character 'salt'
    return random.choice(chars) + random.choice(chars)

用于生成密码:

crypt.crypt("password", getsalt())

*: 长度大于 8 的密码从右往下剥离到 8 个字符长

于 2013-01-05T02:49:10.453 回答