django rest框架-会话身份验证与令牌身份验证,csrf

时间:2019-01-13 13:03:56

标签: django django-rest-framework django-csrf

我将DRF设置为默认设置。我的ajax客户端可以与会话身份验证正常工作。我希望其他远程服务器使用与javascript客户端相同的API。

我的登录代码很简单:

class Login(APIView):
    def post(self, request, *args, **kwargs):

        user = authenticate(username=username, password=password)

        if user is None:
            return Response(status=status.HTTP_401_UNAUTHORIZED)

        login(request, user)
        # ...

问题是,当我从另一个主机(如python requests)使用客户端时,出现CSRF错误。根据DRF文档,我认为我应该改用令牌认证。

问题:

  1. 为什么需要令牌认证? sessionid cookie已经是一个令牌,为什么我不能同时将其用于ajax客户端和软件客户端?因此,请避免为令牌使用另一个单独的db表。

  2. 由于我只想使用会话身份验证,因此如何仅对ajax客户端强制执行CSRF?

2 个答案:

答案 0 :(得分:3)

  1. 使用令牌身份验证并不是强制性的,只是会话身份验证容易受到CSRF攻击。您可以尝试使用CORS机制和CSRF令牌来阻止这种情况,但是它仍然不是完全安全。 坦白地说,令牌身份验证不能完全与浏览器一起使用,因为如果您不使用复杂且复杂的机制来处理令牌,则可以使用浏览器的开发人员工具轻松检索令牌。将其用于第三方应用程序更简单。

  2. 尽管CSRF攻击仅适用于浏览器(Ajax客户端),但是您不应尝试排除它们,因为检查请求是否来自ajax客户端request.is_ajax()的方法取决于客户端是否已设置X-Requested-With标头。攻击者可能会删除此标头。同样,我建议您还添加CORS验证,这是浏览器除Django的CSRF令牌之外,还用于防御CSRF攻击的方法。通常使用Django-cors-headers软件包

  

为什么令牌身份验证不受csrf攻击?对于我来说,这似乎比会议更安全。正如我所看到的,他们两个都使用HTTP标头来传递令牌(令牌认证位于Authorization标头中,会话是一个cookie,它也是标头)

使用Authorization标头发送令牌(您也可以决定使用自定义标头,但这是互操作性的标准),而会话身份验证则使用浏览器自动发送的cookie,这就是为什么容易受到CSRF攻击。对于令牌,客户端必须显式设置标头,以便它必须知道令牌,而攻击者甚至不必知道cookie中存储的内容,因为浏览器只是自动发送该站点的cookie存储中的任何内容。

答案 1 :(得分:2)

您不应该只为ajax客户端启用CSRF保护-这没有任何意义。您如何区分“ ajax”客户端和“普通”客户端?如果会完成,例如通过某些查询参数,攻击者就可以使用此“正常”链接来做坏事。

当您使用基于令牌的身份验证时,攻击者不能仅使用公共URL来透明地对您的请求进行身份验证。这就是为什么仅基于会话的身份验证要求将有效的CSRF令牌包含在请求中的原因。

因此出于安全原因,有2个选项:

  • 要么使用基于会话的身份验证,但是随后您需要在每个请求中发送auth cookie和CSRF令牌;
  • 或使用基于令牌的身份验证,因为您只需要提供身份验证令牌(例如,作为查询参数。
  

我可以使用从标准django_session表获取令牌的令牌身份验证吗?只是将其用作令牌?

理论上,您可以通过编写一些自定义身份验证中间件来实现该目的,该中间件将使用查询参数中的令牌并将其与会话表进行匹配,但这通常是个坏主意。

首先,再使用一个表没有太大的开销,但是如果没有它,您将使系统更难以阅读和维护。

第二,这也会使系统更加脆弱。由于会话和令牌是2个完全不同的实体,因此它们可以具有不同的寿命。会话可以被刷新,它们的TTL可以短于或长于令牌TTL。例如,默认的django会话TTL为2周。您是否要使远程服务器逻辑复杂化以便每2周获取新令牌?或想象令牌被盗用的情况。您是否也要强制ajax客户端注销?