Python 从数据库存储和检索密码的最安全方法

发布于 2024-08-27 18:42:40 字数 99 浏览 5 评论 0原文

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

Looking to store usernames and passwords in a database, and am wondering what the safest way to do so is. I know I have to use a salt somewhere, but am not sure how to generate it securely or how to apply it to encrypt the password. Some sample Python code would be greatly appreciated. Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

娇妻 2024-09-03 18:42:40

将密码+盐存储为哈希值和盐。看看 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)

Store the password+salt as a hash and the salt. Take a look at how Django does it: basic docs and source.
In the db they store <type of hash>$<salt>$<hash> in a single char field. You can also store the three parts in separate fields.

The function to set the password:

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)

The get_hexdigest is just a thin wrapper around some hashing algorithms. You can use hashlib for that. Something like hashlib.sha1('%s%s' % (salt, hash)).hexdigest()

And the function to check the password:

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)
稀香 2024-09-03 18:42:40

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

I think it is best to use a function dedicated to hashing passwords for this. I explain some reasons for this here: https://stackoverflow.com/a/10948614/893857
Nowadays the standard library has a dedicated section in the documentation for hashing password. It even mentions that you should get your salt from a cryptographically secure random source like os.urandom().

二货你真萌 2024-09-03 18:42:40

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

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

I answered this here: https://stackoverflow.com/a/18488878/1661689, and so did @Koffie.

I don't know how to emphasize enough that the accepted answer is NOT secure. It is better than plain text, and better than an unsalted hash, but it is still extremely vulnerable to dictionary and even brute-force attacks. Instead, please use a SLOW KDF like bcrypt (or at least PBKDF2 with 10,000 iterations)

囍笑 2024-09-03 18:42:40

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

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

If you have enough control over both endpoints of the application, the absolute best way is using PAK-Z+.

(Edited: the original version recommended SRP but PAK-Z+ has a proof of security.)

你在我安 2024-09-03 18:42:40

对于 Flask 应用程序或任何 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

For flask application or any python application you can use the werkzeug WSGI web application library, which provides you the option to generate and decode the password with salt and different types of algorithms in a format like this : method$salt$hash

The default salt length is 16 and algo used is sha256

Eg.

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

you can read more about werkzeug security here : https://werkzeug.palletsprojects.com/en/2.0.x/utils/#module-werkzeug.security

海螺姑娘 2024-09-03 18:42:40

这是一个更简单的方法(取自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个字符长的

Here is a simpler way (taken from effbot), provided passwords with a length greater than 8 will not be a problem*:

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)

for generate the password :

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

*: A password with a length greater than 8 is stripped from the right down to 8 chars long

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文