Django 1.9 "Common Password Validator" - 奇怪的行为

Django 1.9 "Common Password Validator" - Strange Behaviour

我正在尝试用我自己的相同版本替换内置的 common-passwords.txt.gz 文件,该文件应该包含前 1,000 个常用密码,其中包含我所在国家/地区的前 10,000 个常用密码,但是我已经遇到了一些相当奇怪的行为。

  1. 首先,我直接将 Django 的 common-passwords.txt.gz 文件 (4KB) 替换为我自己的包含与 Django 相同的 utf-8 编码的 .txt 文件(34KB),然后重新启动测试服务器。将用户密码更改为 "password" 时,它不会像 Django 的通用密码文件那样引发预期的错误。

    内置密码列表和我的新密码列表的第一行都以 123456password12345678qwerty123456789... 开头,所以它显然应该这样做。

    当我将一些额外的密码附加到他们的通用密码文件时,它似乎可以正常工作,如果我尝试将它们用作密码,则会引发错误,所以我认为它没有缓存在某处或任何地方就这样。

    通用密码列表或 gzip.open(password_list_path).read().decode('utf-8').splitlines() 函数是否有某种内置文件大小限制?

  2. 其次,试图弄清楚上面的问题让我遇到了一个奇怪的错误。使用 Django 内置的 common-passwords.txt.gz(其中第一行以 123456password12345678qwerty123456789... 开头)成功引发了 "password" 和 "password1" 的验证错误,但 "password12" 或 "password123"!

    正如我所读,Django 验证代码基本上检查提交的密码是否 is in 来自通用密码文件的每一行,我找不到任何代码可以免除超过一定长度的密码进行验证。我是不是遗漏了什么或者这是一个错误?

Django 1.9中的"common password validation"函数在\venv\Lib\site-packages\django\contrib\auth\password_validation.py中找到,相关的class如下:

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.")

终于一探究竟!

Django 内置的通用密码验证文件中包含的密码之间存在某种不可见的未呈现字符,这解释了我遇到的两个问题。

我更改了我的前 10k 个常用密码文件,改为在它们之间使用通常的换行符,现在一切正常!即使现在有 10 倍多的密码供它比较,它仍然几乎可以立即运行!

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