我将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文档,我认为我应该改用令牌认证。
问题:
为什么需要令牌认证? sessionid cookie已经是一个令牌,为什么我不能同时将其用于ajax客户端和软件客户端?因此,请避免为令牌使用另一个单独的db表。
由于我只想使用会话身份验证,因此如何仅对ajax客户端强制执行CSRF?
答案 0 :(得分:3)
使用令牌身份验证并不是强制性的,只是会话身份验证容易受到CSRF攻击。您可以尝试使用CORS机制和CSRF令牌来阻止这种情况,但是它仍然不是完全安全。 坦白地说,令牌身份验证不能完全与浏览器一起使用,因为如果您不使用复杂且复杂的机制来处理令牌,则可以使用浏览器的开发人员工具轻松检索令牌。将其用于第三方应用程序更简单。
尽管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个选项:
我可以使用从标准django_session表获取令牌的令牌身份验证吗?只是将其用作令牌?
理论上,您可以通过编写一些自定义身份验证中间件来实现该目的,该中间件将使用查询参数中的令牌并将其与会话表进行匹配,但这通常是个坏主意。
首先,再使用一个表没有太大的开销,但是如果没有它,您将使系统更难以阅读和维护。
第二,这也会使系统更加脆弱。由于会话和令牌是2个完全不同的实体,因此它们可以具有不同的寿命。会话可以被刷新,它们的TTL可以短于或长于令牌TTL。例如,默认的django会话TTL为2周。您是否要使远程服务器逻辑复杂化以便每2周获取新令牌?或想象令牌被盗用的情况。您是否也要强制ajax客户端注销?