Django:取消用户密码,但仍允许重置密码

3
我想重置/取消我的用户密码,他们应该被强制使用“密码重置”,并设置一个新的密码,符合新密码验证器的要求。
我在Django文档中找到了信息,所以set_unusable_password()不是一个选项,因为之后不能进行重置。我发现使用user.password = ''可以解决问题——用户无法登录,密码重置也能正常工作。
尽管如此,这个解决方案还是有些别扭,而且我找不到关于这个主题的任何真正的资源——从安全角度来看怎么样等等。
1个回答

1

你说得对,使用User.set_unusable_password后无法重置密码。

https://docs.djangoproject.com/en/4.0/topics/auth/default/#django.contrib.auth.views.PasswordResetView中可以看到:

标记为不可用密码的用户(请参见set_unusable_password())不允许请求密码重置,以防在使用外部身份验证源(如LDAP)时被滥用。

解决方案1-覆盖默认Django行为

使用视图和表单类,覆盖django.contrib.auth.forms.PasswordResetForm.get_users方法,该方法根据电子邮件地址获取User实例。 重新实现它,不使用if user.has_usable_password条件,这样您就可以实际利用User.set_unusable_password方法。

这样,您就可以保持Django内部使用的规范,而“无效”的密码永远不会与外部输入匹配。

解决方案2-空值或空字符串

正如您所提到的,使用None值或空字符串应该可以解决问题。

我看到的主要缺点是,如果在身份验证逻辑中引入了代码错误/回归,它可能会接受空/空白密码并将其与DB值匹配。攻击者将获得访问这些帐户的权限。

例如,如果用户输入一个仅包含不允许的字符的字符串,并且验证逻辑接受它,因为它是非空的,然后剥离所有无效字符。或者用户输入一个仅包含空格的字符串,这些空格被接受但稍后被修剪。在这两种情况下,它可能导致一个空字符串,实际上将被测试与用户的密码匹配并连接用户。

(当然还有很多其他可能的解决方案:))


顺便提一下,关于Django 2.1的一个有趣的注释,请参见https://docs.djangoproject.com/en/4.0/releases/2.1/#miscellaneous

User.has_usable_password()和is_password_usable()函数不再返回False,如果密码为None或空字符串,或者密码使用的哈希器不在PASSWORD_HASHERS设置中。这个未记录的行为是Django 1.6中的一个回归,并且阻止了使用此类密码的用户请求密码重置。审核您的代码以确认您对这些API的使用不依赖于旧行为。

因此,如果您使用的是Django <1.6或>=2.1,则必须处理该问题。


我不同意。如果我使用 set_unusable_password(),那么我将无法再请求重置密码,这是我的本意,不是吗?如果我手动将其设置为 None 或空字符串,则将无法登录,但是可以进行密码重置。但在1.6到2.1版本的Django中则不行。我之前并不知道这个问题。与此同时,我相信我的解决方案很好...将密码设置为空字符串。 - benzkji
确实,我的错。我会编辑评论。然而,None 密码也会导致无法使用的密码。空字符串可能是更好的选择。 - David
很好,感谢提出解决方案1以及空字符串作为密码可能存在的注意事项。 - benzkji

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