在Django 1.9中创建一个旧[哈希]密码的表格

3

我想要做什么:

  • 创建一个数据库表格,记录最近使用过的两个密码(不包括当前密码)。

我已经了解到的内容:

  • 我已经发现了 check_password('123') 函数。
    • 据我所知,在运行 User.set_password() 之前,该函数将新输入的密码与当前密码进行比较。
  • 我已经创建了一张表格,用于存储用户名和最近使用过的两个密码(不包括当前密码)。
  • 我已经发现了两个不同的哈希值:
    • User.get_session_auth_hash()
      • 我不确定这是否用于密码哈希?
    • User.set_password.hash()
      • 同样,我不确定这是否用于密码哈希?

我的问题:

在我的 Python shell 中(在我的项目下),我使用 User.set_password() 并在运行 User.password 后设置相同的当前密码。然后当我再次运行 User.password 时,发现哈希值不同。

我应该如何保存先前的密码哈希方法,并重新使用它来重新哈希密码,以便与先前哈希过的密码进行比较?

相同密码的密码哈希示例:

u = User.objects.get(username='username')  # set user object
u.password  # display current hashed password (password is set to '123')
# pbkdf2_sha256$24000$2lTIbv4a3deG$ElefaaF0aaFh6y50ENNT2pCNQKpoNvYBQ1nZojz8sUg=
u.get_session_auth_hash()
# 8ad1d1d3ac6d442b241f79d447a01ef561960ea4
u.set_password.__hash__()
# -123 (not really, just not sure if safe to post)
u.set_password('123')
# pbkdf2_sha256$24000$VVnXSQdHAak4$FJv3SH/m9jkBcUXAuxJbm0wyhjI+3JHccF7+D2s4qvs=
u.get_session_auth_hash()
# 8416cf2da88c2905862a93464317d779cf938211
u.set_password.__hash__()
# -123 (has not changed after password change)

这只是我在提议的shell中运行我的命令。我只能想象哈希过程中会有随机盐的添加。我认为这可能会有用。

在这个网站上,我的研究引导我到了这篇文章:

如何在Django 1.9中实现更改密码表单

研究更新

我假设session_auth_hash被用于哈希。我开始认为将此值存储在数据库中可能不安全,但我只能假设它已经存储在某个地方,因为Django需要使用它来哈希输入的密码(登录时)以验证它是否与相同的密码一致......我觉得我只需要分解set_password()函数...

最终想法

是否存在潜在的安全问题?

为了可能回答自己的问题:如果存储盐不是一个好主意,那么存储从Django中哈希出的加密密码也是不好的主意。如果有人已经访问了我的数据库,他们将能够在数据库中找到已经存储的哈希密码中的盐。我不认为这有太大的区别,除了为想要攻击者分离盐。

1个回答

2

潜在突破

当打印出哈希密码时,它的布局如下(根据Django网站):<algorithm>$<iterations>$<salt>$<hash>

这里是一个哈希示例(明文密码为123):

pbkdf2_sha256$24000$tYZnlj3alG8Q$DuDmimgvgwFjiRT2B42/4oeMbNkKA/DVTCFXPte3Yic=

我们可以看到使用的算法是pbkdf2,哈希值为sha256(Django 1.9的默认值(我确定其他版本也是如此,但我个人没有确认)。迭代似乎在所有尝试中都很普遍(24000,有人能确认吗?),盐在这种情况下是明显可识别的(tYZnlj3alG8Q)。

如果我导入from django.contrib.auth import hashers,我可以运行hashers.make_password('123', salt='tYZnlj3alG8Q'),它会打印出相同的哈希值!

from django.contrib.auth import hashers
from django.contrib.auth.models import User
>>> u = User.objects.get(username='test')
>>> print u.password
pbkdf2_sha256$24000$tYZnlj3alG8Q$DuDmimgvgwFjiRT2B42/4oeMbNkKA/DVTCFXPte3Yic=
>>> test = u.password
>>> test1 = hashers.make_password('123', salt='tYZnlj3alG8Q')
>>> print test1
pbkdf2_sha256$24000$tYZnlj3alG8Q$DuDmimgvgwFjiRT2B42/4oeMbNkKA/DVTCFXPte3Yic=
# an extra confirmation
>>> test == test1
True

我打算这样设置我的表格:
ID --- username --- prev1 --- salt1 --- prev2 --- salt2

1  --- test     --- 123   --- ewew@ --- 321   --- saqd!

2  --- test1    --- 456   --- kaka% --- 654   --- ji;l(

测试背后的逻辑与以下类似:

def old_pass_check():
    old_pass_1 = "prev1 pulled from DB"
    salt_1 = "salt1 pulled from DB"
    old_pass_2 = "prev2 pulled from DB
    salt_2 = "salt2 pulled from DB
    new_pass = "entered_pass"

    old_hash_1 = hashers.make_password('new_pass', salt=salt_1)
    old_hash_2 = hashers.make_password('new_pass', salt=salt_2)
    new_hash_1 = hashers.make_password('new_pass', salt=salt_1)
    new_hash_2 = hashers.make_password('new_pass', salt=salt_2)

    if new_hash_1 in {old_hash_1, old_hash_2}:
        return error
    elif new_hash_2 in {old_hash_1, old_hash_2}:
        return error

    else:
        set_password(new_pass)
        *logic to update latest used password and salt into DB table
         making sure only 2 latest passwords are there*

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接