Django 1.9“常用密码验证器”的奇怪行为

3
我试图用包含我国前10000个常见密码的文件替换内置的common-passwords.txt.gz文件,该文件据说包含了前1000个常见密码。但是我遇到了一些奇怪的行为。
首先,我直接用我的包含相同utf-8编码的.txt文件(大小为34KB)替换了Django的common-passwords.txt.gz文件(大小为4KB),然后重新启动测试服务器。当我将用户的密码更改为"password"时,它没有像使用Django的常见密码文件那样引发预期的错误。
内置密码列表和我的新密码列表的第一行都以123456password12345678qwerty123456789...开头,所以它显然应该有反应。当我将一些额外的密码附加到他们的常用密码文件中时,它似乎按照预期工作,并且如果我尝试将它们用作密码,则会引发错误,因此我不认为它被缓存在某个地方或类似的情况。
是否存在内置文件大小限制来限制常见密码列表或gzip.open(password_list_path).read().decode('utf-8').splitlines()函数?
其次,尝试解决上述问题导致了一个奇怪的错误。使用Django内置的common-passwords.txt.gz(其中第一行以123456password12345678qwerty123456789...开头)成功引发了“password”和“password1”的验证错误,但未对“password12”或“password123”引发错误!
据我所知,Django验证代码基本上检查提交的密码是否在常见密码文件中的每一行中,我找不到任何免除较长密码验证的代码。我是漏看了什么还是这是一个bug?
Django 1.9中的“常见密码验证”函数位于\venv\Lib\site-packages\django\contrib\auth\password_validation.py,相关类如下:
class CommonPasswordValidator(object):
"""
Validate whether the password is a common password.

The password is rejected if it occurs in a provided list, which may be gzipped.
The list Django ships with contains 1000 common passwords, created by Mark Burnett:
https://xato.net/passwords/more-top-worst-passwords/
"""
    DEFAULT_PASSWORD_LIST_PATH = os.path.join(
        os.path.dirname(os.path.realpath(upath(__file__))), 'common-passwords.txt.gz'
    )

    def __init__(self, password_list_path=DEFAULT_PASSWORD_LIST_PATH):
        try:
            common_passwords_lines = gzip.open(password_list_path).read().decode('utf-8').splitlines()
        except IOError:
            with open(password_list_path) as f:
                common_passwords_lines = f.readlines()

        self.passwords = {p.strip() for p in common_passwords_lines}

    def validate(self, password, user=None):
        if password.lower().strip() in self.passwords:
            raise ValidationError(
                _("This password is too common (it would be trivial to crack!)"),
                code='password_too_common',
            )

    def get_help_text(self):
        return _("Your password can't be a commonly used password.")

1
我认为用覆盖文件的方式替换文件不是一个好主意。这里有一个使用验证器和自定义路径的例子:https://github.com/orcasgit/django-password-validation/blob/master/password_validation/test/test_validators.py#L151。你能提供一下你将在哪里使用验证器的更多上下文信息吗? - Panta Cuzino
我试图在我的应用程序中的每个人可以创建密码的地方都使用验证器(目前仅限管理员界面,但最终也会用于自定义表单!),这就是为什么我试图直接用我的自定义列表替换内置列表的原因。你能否使用你所用版本的Django测试一下,看看它是否会对Password12或Password123引发错误? - TimJ
1个回答

1

终于查明了问题的根源!

Django内置的常见密码验证文件中间有某种看不见的未呈现字符,这解释了我遇到的两个问题。

我将我的前10000个常见密码文件改为通常的换行符并在其中添加,现在一切都很好!即使现在它需要比较的密码数量增加了10倍,但它仍然几乎可以瞬间完成!

我已经将我的10000个最常见密码文件上传到GitHub上,以供将来遇到此问题或想要改进Django内置的常见密码验证的人使用:https://github.com/timboss/Django-Common-Password-Validation/


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