我如何利用werkzeug.安全的check_password_hash函数根据现有的salt sha1密码哈希验证正确的密码

2024-09-30 01:31:22 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在开发一个新的python应用程序,它需要验证数据库中现有的用户凭证。我们的许多遗留应用程序都是建立在PHP的Symfony框架上的,而这些密码散列和salt就是从这里产生的。在数据库算法(sha1)中,salt和用户的哈希密码被保留。我正试图在结合werkzeug.security模块的check_password_hash函数中使用这些信息来正确验证密码。但是,到目前为止我还没有成功。在

出于演示目的,我创建了一个测试用户,数据库包含该用户的以下值。在

测试用户值

algorithm:sha1
salt:e40e1e9addc186828a554a71527342c
password(哈希):784517f57fbe61179960739e29d7ae925aa4fd5b

测试用户的实际密码是123456

我尝试了以下方法来验证密码

注意事项:
1哈希格式改编自werkzeug.security文档
2比较哈希法是从this StackOverflow answer改编而来的

from werkzeug.security import generate_password_hash
from werkzeug.security import check_password_hash

# Attempt 1 - Results in False
check_password_hash('sha1$e40e1e9addc186828a5554a71527342c$784517f57fbe61179960739e29d7ae925aa4fd5b','123456')

# Attempt 2 - Results in False
check_password_hash('pbkdf2:sha1$e40e1e9addc186828a5554a71527342c$784517f57fbe61179960739e29d7ae925aa4fd5b','123456')

# Attempt 3
# Step 1: Append the salt_value to the given password and hash it using the same hash function.
generate_password_hash('123456$e40e1e9addc186828a5554a71527342c','sha1')
# sha1$9lUceSsd$60f7dcb3ff9c22d4613e59fcbfed0c463ee4189e
# Step 2: Compare the hash to the hash in the database
# 60f7dcb3ff9c22d4613e59fcbfed0c463ee4189e != 784517f57fbe61179960739e29d7ae925aa4fd5b

# Attempt 4 - Same steps as Attempt 3 except adding salt_length argument
# Step 1: Append the salt_value to the given password and hash it using the same hash function.  
generate_password_hash('123456$e40e1e9addc186828a5554a71527342c','sha1',len('e40e1e9addc186828a5554a71527342c'))
# sha1$EbPv6DP0wMyu02UpA6ZYazFvvYvZTVI1$b8252583fea027d42af20c0d0f3eac3fbf468bd1
# Step 2: Compare the hash to the hash in the database
# b8252583fea027d42af20c0d0f3eac3fbf468bd1 != 784517f57fbe61179960739e29d7ae925aa4fd5b

有谁能提供一些我做错了什么的见解吗?我是否应该尝试使用其他库,如passlib?我希望这个模块足够了,因为我对它很熟悉,已经创建了一些我们现有的python应用程序,这些应用程序将它用于新的用户注册,但是在一个单独的数据库中。在

Edit-显示使用werkzeug.securitycheck_password_hash函数

^{pr2}$

Tags: the用户in数据库应用程序密码checkpassword
1条回答
网友
1楼 · 发布于 2024-09-30 01:31:22

werkzeug.generate_password_hash要生成salt值。查看源代码,我们可以看到使用生成的salt值调用_hash_internal。在

def generate_password_hash(password, method="pbkdf2:sha256", salt_length=8):
    """Hash a password with the given method and salt with a string of
    the given length. The format of the string returned includes the method
    that was used so that :func:`check_password_hash` can check the hash.

    The format for the hashed string looks like this::

        method$salt$hash

    This method can **not** generate unsalted passwords but it is possible
    to set param method='plain' in order to enforce plaintext passwords.
    If a salt is used, hmac is used internally to salt the password.

    If PBKDF2 is wanted it can be enabled by setting the method to
    ``pbkdf2:method:iterations`` where iterations is optional::

        pbkdf2:sha256:80000$salt$hash
        pbkdf2:sha256$salt$hash

    :param password: the password to hash.
    :param method: the hash method to use (one that hashlib supports). Can
                   optionally be in the format ``pbkdf2:<method>[:iterations]``
                   to enable PBKDF2.
    :param salt_length: the length of the salt in letters.
    """
    salt = gen_salt(salt_length) if method != "plain" else ""
    h, actual_method = _hash_internal(method, salt, password)
    return "%s$%s$%s" % (actual_method, salt, h)

如果我们用您的sha1方法调用_hash_internal,并提供salt/密码,则得到一个不同的哈希

^{pr2}$

我认为您需要重新访问PHP代码,看看这些值是如何生成的。在

编辑:根据你的评论

In [138]: werkzeug.security._hash_internal('sha1', '', 'e40e1e9addc186828a5554a71527342c123456')                                                                                      
Out[138]: ('784517f57fbe61179960739e29d7ae925aa4fd5b', 'sha1')

如果要使用check_password_hash,则不必在哈希中设置salt,而是将其添加到密码中:

In [148]: werkzeug.check_password_hash('sha1$$784517f57fbe61179960739e29d7ae925aa4fd5b', 'e40e1e9addc186828a5554a71527342c123456')                                                    
Out[148]: True

如果我们查看源代码,我们可以看到check_password_hashpwhash中提取methodsalt和{},然后验证散列password匹配hashval。我不熟悉PHP中的散列,但似乎密码是“加盐”的,然后不加盐地进行散列(到目前为止)werkzeug.安全不管怎样,都会引起关注)。在

def check_password_hash(pwhash, password):
    """check a password against a given salted and hashed password value.
    In order to support unsalted legacy passwords this method supports
    plain text passwords, md5 and sha1 hashes (both salted and unsalted).

    Returns `True` if the password matched, `False` otherwise.

    :param pwhash: a hashed string like returned by
                   :func:`generate_password_hash`.
    :param password: the plaintext password to compare against the hash.
    """
    if pwhash.count("$") < 2:
        return False
    method, salt, hashval = pwhash.split("$", 2)
    return safe_str_cmp(_hash_internal(method, salt, password)[0], hashval)

相关问题 更多 >

    热门问题