django - 切换到django 3并返回django 2后无法登录Django项目
问题描述
我有一个 Django 2.2 项目,它在一堆不同的服务器上运行,但它们使用相同的数据库。
我创建了一个分支来迁移到 Django 3,但并非所有服务器都会同时迁移。
我使用 Argon2:
# https://docs.djangoproject.com/en/dev/ref/settings/#password-hashers
PASSWORD_HASHERS = [
'django.contrib.auth.hashers.Argon2PasswordHasher',
'django.contrib.auth.hashers.PBKDF2PasswordHasher',
'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
'django.contrib.auth.hashers.BCryptPasswordHasher',
]
当我在开发分支中切换到 django 3.2 时,一切正常。但是,当我回到 Django 2.2 时,我开始收到如下错误:
- 模板语法错误
- 填充错误 (
exception location: .../python3.6/base64.py in b64decode
)
只需删除 cookie 并重新加载即可解决这些问题。所以我猜测它们与 django 3.1 中从 sha1 到 sha256的新默认散列算法的变化有关。
无论如何,重新加载后,页面工作。但是当我尝试登录时,它无法识别凭据。
然后我从备份中恢复了数据库并可以登录 django 2.2。
我再次尝试使用以下设置在 django 3.2 上运行:
DEFAULT_HASHING_ALGORITHM = 'sha1'
现在,当切换回 2.2 时,我在页面加载时没有收到错误(我不需要删除 cookie),但凭据仍然不起作用。
对我来说,切换到 django 3.2 后,数据库中密码的哈希值发生了变化。
django 3是否有可能重写数据库中的密码?任何人都可以指出解决方案或尝试的东西吗?
谢谢你。
解决方案
解决方案 TL;DR
好吧,似乎如果你使用 Argon2 哈希器,Django 确实会更新存储的密码,如果你想暂时避免它,你必须更新到 Django 3.1,直到准备好移动到 3.2 或子类化哈希器。
比较存储的密码
由于我可以在 Django 3 中访问生产数据库(django 2.2)和本地数据库,因此我比较了用户的密码:
Django 2.2(2019 年 4 月发布)
算法:argon2类型:argon2i版本:19内存成本:512时间成本:2并行度:2盐:UVn **********哈希:QVt ************** ***
Django 3.2
算法:argon2品种:argon2id版本:19内存成本:102,400时间成本:2并行度:8盐:pHQzc2 ****************哈希:flj ******** ********
是的,它们是不同的!
Django 3.2 发行说明讲述了默认 Argon2 哈希器的变化:
django.contrib.auth
PBKDF2 密码哈希的默认迭代次数从 216,000 增加到 260,000。
Argon2 密码哈希的默认变体更改为 Argon2id。memory_cost 和并行度分别增加到 102,400 和 8 以匹配 argon2-cffi 默认值。
增加 memory_cost 会将所需内存从 512 KB 推到 100 MB。这仍然相当保守,但会在内存受限的环境中导致问题。如果是这种情况,现有的哈希可以被子类化以覆盖默认值。
Argon2、MD5、PBKDF2、SHA-1 密码哈希器的默认盐熵从 71 位增加到 128 位。
这是改变的门票:
#30472 应该支持 Argon2id 并成为 Argon2PasswordHasher 的默认品种
查看中的代码django.contrib.auth.hashers
,我可以看到密码已在以下位置修改check_password
:
def check_password(password, encoded, setter=None, preferred='default'):
...
hasher_changed = hasher.algorithm != preferred.algorithm
must_update = hasher_changed or preferred.must_update(encoded)
is_correct = hasher.verify(password, encoded)
...
class Argon2PasswordHasher(BasePasswordHasher):
...
def must_update(self, encoded):
decoded = self.decode(encoded)
current_params = decoded['params']
new_params = self.params()
...
def params(self):
argon2 = self._load_library()
# salt_len is a noop, because we provide our own salt.
return argon2.Parameters(
type=argon2.low_level.Type.ID,
version=argon2.low_level.ARGON2_VERSION,
salt_len=argon2.DEFAULT_RANDOM_SALT_LENGTH,
hash_len=argon2.DEFAULT_HASH_LENGTH,
time_cost=self.time_cost,
memory_cost=self.memory_cost,
parallelism=self.parallelism,
)
此行将type=argon2.low_level.Type.ID
argon2 类型从 更改argon2i
为argon2id
。其余的变化很明显。
我不确定这是否是真正的过程,但我想它是这样的:
- 你输入密码
- 使用旧算法检查密码
- 如果匹配,则使用新算法重新散列并保存
(如果我错了,我会很高兴知道)
回顾一下:我的问题
我的问题是我有几个不同的 Django 2 项目使用相同的公共核心代码和相同的数据库。尽管它们是不同的项目,但有许多用户可以访问所有这些项目。我想从最不敏感的地方开始逐步更新它们,看看是否出现错误。
解决方案 1
升级到 Django 3.1 而不是 3.2。这将允许我逐步更新不同的项目,而不会中断用户访问。一旦所有项目在 3.1 版本中运行了一段时间并修复了出现的任何错误,我就可以更有信心地将它们同时更新到 django 3.2。这是我已经测试过并且有效的(它不会更改密码)。
解决方案 2
子类化django.contrib.auth.hashers.Argon2PasswordHasher
哈希,因此它不会更新密码。在设置中指向它,PASSWORD_HASHERS
当所有项目在 django 3.2 中顺利运行时将其删除。
推荐阅读
- python - 在磁盘上更快地保存图像
- python - 将数据与 pandas 相结合
- syslog-ng - 发送需要 Syslog-ng 行消息 - 不需要时间戳 - 不需要标头
- javascript - 在nodejs中将txt文件转换为json
- html - 用户输入内容时如何在输入中粘贴单词
- javascript - nodejs 将 wav、mp3 转换为 AudioBuffer
- mongodb - mongodb排序规则不适用于facet阶段的insinde聚合
- ios - 扑。如何更新PageView内的GridView内的文本?
- fonts - SwiftUI:读取给定字符串的边界矩形
- vba - 从共享的 Outlook 邮箱自动下载带有特定主题的附件 PDF 文件