Django 密码在数据库中的存储格式是什么?
你知道Django是怎么存储密码的吗?它的存储方式是这样的:
sha1$a1976$a36cc8cbf81742a8fb52e221aaeab48ed7f58ab4
这里面有个格式是“哈希类型 $盐 $哈希”。我想问的是,$哈希是怎么来的?是把密码和盐混合在一起然后再进行哈希处理,还是说有其他的方式呢?
3 个回答
13
很长一段时间,直到1.3版本,Django确实采用了一种不负责任的做法,就是用简单的SHA1算法和一个太短的盐值来存储密码信息。这种方法自1979年以来就已经过时了。用这种方式存储的密码非常容易受到暴力破解攻击。想了解更多原因,可以查看关于密码哈希的安全讨论。
自2012年1.4版本以来,Django默认使用一种基于标准密钥派生函数PBKDF2的哈希算法,这种算法的迭代次数是可以配置的,默认值在每个版本中都会增加(在1.7版本中是20000次)。它还支持bcrypt,并且与早期版本兼容,用户登录时会自动升级密码哈希。想了解更多,可以查看Django中的密码管理 | Django文档。
22
根据文档:
哈希类型可以是 sha1(默认)、md5 或 crypt,这些是用来对密码进行单向加密的算法。盐是一个随机字符串,用来给原始密码加盐,以生成哈希。
根据set_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)
文档中提到,哈希是由盐、算法和密码组合后进行加密的结果。
46
和往常一样,记得查看源代码:
# root/django/trunk/django/contrib/auth/models.py
# snip
def get_hexdigest(algorithm, salt, raw_password):
"""
Returns a string of the hexdigest of the given plaintext password and salt
using the given algorithm ('md5', 'sha1' or 'crypt').
"""
raw_password, salt = smart_str(raw_password), smart_str(salt)
if algorithm == 'crypt':
try:
import crypt
except ImportError:
raise ValueError('"crypt" password algorithm not supported in this environment')
return crypt.crypt(raw_password, salt)
if algorithm == 'md5':
return md5_constructor(salt + raw_password).hexdigest()
elif algorithm == 'sha1':
return sha_constructor(salt + raw_password).hexdigest()
raise ValueError("Got unknown password algorithm type in password.")
我们可以看到,密码的摘要是通过把“盐”(salt)和密码连接在一起,然后用选定的哈希算法处理得到的。接着,算法的名称、原始的盐和密码的哈希值用“$”符号分开连接,形成最终的摘要。
# Also from root/django/trunk/django/contrib/auth/models.py
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)
为了验证密码,Django只需检查相同的盐和相同的密码是否能得到相同的摘要。