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

use*_*803 3 django django-csrf django-rest-framework

我使用默认设置设置了 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)
        # ...
Run Code Online (Sandbox Code Playgroud)

问题是当我使用来自另一台主机的客户端时,例如 python requests,我收到 CSRF 错误。根据 DRF 文档,我认为我应该改用令牌身份验证。

问题:

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

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

Ken*_*ars 5

  1. 使用令牌认证并不是必须的,只是会话认证容易受到 CSRF 攻击。您可以尝试使用 CORS 机制和 CSRF 令牌来防止这种情况发生,但它仍然不完全安全。老实说,令牌身份验证并不完全适用于浏览器,因为如果您不使用非常复杂和精密的机制来处理令牌,则可以使用浏览器的开发人员工具轻松检索令牌。将它用于第三方应用程序更简单。

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

为什么令牌认证不受 csrf 攻击?对我来说,它似乎并不比会话更安全。正如我所见,它们都使用 HTTP 标头来传递令牌(令牌身份验证在 Authorization 标头中,而 session 是一个 cookie,它也是一个标头)

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