【问题标题】:django rest framework - session auth vs token auth, csrfdjango rest 框架 - session auth vs token auth, csrf
【发布时间】:2019-06-07 17:04:07
【问题描述】:

我已将 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 客户端和软件客户端?因此避免为令牌使用另一个单独的数据库表。

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

【问题讨论】:

  • 你能展示你的requests客户端的代码吗?您需要在那里使用会话对象才能使 cookie 工作 - 假设您正在这样做,您能否明确检查会话对象持有的 cookie 以确保它们与浏览器的操作相匹配?
  • 我正在使用 requests.session() 对象。问题是我需要在每个请求中发送 csrftoken

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


【解决方案1】:

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

当您使用基于令牌的身份验证时,攻击者不能只使用通用 URL 来使您的请求得到透明身份验证。这就是为什么只有基于会话的身份验证需要在请求中包含有效的 CSRF 令牌。

因此出于安全原因,有两种选择:

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

我可以使用从标准 django_session 表中获取令牌的令牌身份验证吗?就用它作为令牌?

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

首先,多使用一个表并没有这么大的开销,但是如果没有它,系统就会更难阅读和维护。

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

【讨论】:

  • 我可以使用从标准 django_session 表中获取令牌的令牌身份验证吗?只是用它作为令牌?
  • 其实我不希望令牌永远存在。我确实想要到期日期,就像会话一样。令牌表的唯一优点是 user_id 列,这并不是一个很大的优势。但我想如果这是正确的方法,我会去 authtoken
【解决方案2】:
  1. 使用 Token Authentication 并不是必须的,只是 Session Authentication 容易受到 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 存储中为该站点存储的任何内容。

【讨论】:

  • 为什么令牌认证不受csrf攻击?对我来说,它似乎并不比会话更安全。正如我所看到的,它们都使用 HTTP 标头来传递令牌(令牌身份验证在 Authorization 标头中,会话是一个 cookie,它也是一个标头)
  • 使用令牌认证的坏人需要知道你的令牌(否则他会用自己的令牌发送请求,这没有意义)。基于会话的身份验证允许他透明地使用您的会话cookie,因此请求将从您的帐户完成。
猜你喜欢
  • 2018-07-31
  • 2017-08-19
  • 2019-06-26
  • 2017-04-30
  • 1970-01-01
  • 2014-01-14
  • 2021-03-10
  • 2016-07-08
  • 2019-12-06
相关资源
最近更新 更多