代码之家  ›  专栏  ›  技术社区  ›  cutteeth

为什么django的默认身份验证后端在引发UserModel后调用set_password。是否存在NotExist异常?

  •  4
  • cutteeth  · 技术社区  · 9 年前

    我正在为从django的AbstractUser继承的自定义用户模型编写自定义身份验证后端。我已经检查了django的默认身份验证后端,看到用户对象是使用username和 UserModel._default_manager.get_by_natural_key(username) authenticate()如下

    def authenticate(self, username=None, password=None, **kwargs):
            UserModel = get_user_model()
            if username is None:
                username = kwargs.get(UserModel.USERNAME_FIELD)
            try:
                user = UserModel._default_manager.get_by_natural_key(username)
                if user.check_password(password):
                    return user
            except UserModel.DoesNotExist:
                # Run the default password hasher once to reduce the timing
                # difference between an existing and a non-existing user (#20760).
                UserModel().set_password(password)
    

    我已经编写了一个自定义aut后端,但出于好奇,我问这个问题:为什么在DoesNotExist异常时要检查密码?

    我已经试过了 ipdb 在authenticate方法中,并验证在获取不存在用户的用户名时,控制流将转到except块。还有一个 UserModel().set_password(password) 已在终端中发布。由于不确定后台发生了什么,我检查了 set_password() 属于 auth.models .但它只是提高了 NotImplementedError 例外我不知道这有什么帮助。

    还有如何 raise a UserDoesNotExist or django.core.exceptions.ObjectDoesNotExist exception correctly 在自定义身份验证后端的用户模型上执行失败的对象获取操作时?想法是停止执行并向用户提供正确的反馈消息,而不是引发异常并尝试settings.py中authentication_BACKENDS()中给出的下一个身份验证后端。

    TIA公司

    2 回复  |  直到 9 年前
        1
  •  4
  •   Daniel Roseman    9 年前

    这条评论准确地解释了原因。如果它立即返回False,将比不存在的用户花费更少的时间。然后,攻击者将能够区分现有和不存在的用户名。

        2
  •  4
  •   pymarco    5 年前

    您应该阅读以下内容:

    https://code.djangoproject.com/ticket/20760

    尝试使用django.contrib进行身份验证时。auth,如果用户不存在,authenticate()函数几乎会立即返回None,而当用户存在时,所尝试的密码会被散列并与存储的密码进行比较,这会花费更长的时间。这允许攻击者根据身份验证尝试的响应时间推断给定帐户是否存在。

    推荐文章