django rest framework - session auth vs token auth, csrf
django rest framework - session auth vs token auth, 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 文档,我认为我应该改用令牌身份验证。
问题:
为什么需要令牌认证? sessionid cookie 已经是一个令牌,为什么我不能将它同时用于 ajax 客户端和软件客户端?因此避免为令牌使用另一个单独的数据库 table。
因为我只想使用会话身份验证,如何只对 ajax 客户端实施 CSRF?
您不应该仅为 ajax 客户端启用 CSRF 保护——这没有任何意义。您如何区分 "ajax" 客户端和 "normal" 客户端?如果它会完成,例如通过一些查询参数,那么攻击者就可以使用这个 "normal" link 来做坏事。
当您使用基于令牌的身份验证时,攻击者不能仅使用通用 URL 来透明地对您的请求进行身份验证。这就是为什么只有基于会话的身份验证需要将有效的 CSRF 令牌包含在请求中。
因此出于安全原因,有 2 个选项:
- 要么使用基于会话的身份验证,但是您需要在每次请求时发送身份验证 cookie 和 CSRF 令牌;
- 或使用基于令牌的身份验证,这更简单,因为您只需要提供身份验证令牌,例如作为查询参数。
Can I use token authentication that gets the token from the standard django_session table? just use that as token?
理论上,您可以通过编写一些自定义身份验证中间件来实现这一点,这些中间件将使用查询参数中的令牌并将其与会话 table 匹配,但这通常是个坏主意。
首先,再使用一个 table 并没有那么大的开销,但是如果没有它,系统将更难阅读和维护。
其次,它也会使系统更加脆弱。由于会话和令牌是 2 个完全不同的实体,因此它们可以具有例如不同的寿命。会话可以刷新,它们的 TTL 可以比令牌 TTL shorter/longer。例如,默认的 django 会话 TTL 是 2 周。您想使远程服务器逻辑复杂化以每 2 周获取一次新令牌吗?或者想象一下令牌被泄露的情况。您是否也想强制 ajax 客户端注销?
使用令牌认证并不是必须的,只是 Session 认证容易受到 CSRF 攻击。您可以尝试使用 CORS 机制和 CSRF 令牌来防止这种情况,但它仍然不完全安全。
老实说,令牌身份验证并不完全适用于浏览器,因为如果您不使用非常复杂和精密的机制来处理令牌,则可以使用浏览器的开发人员工具轻松检索令牌。将它用于 third-party 个应用程序更简单。
虽然 CSRF 攻击只适用于浏览器(Ajax 客户端),你不应该试图排除它们,因为检查请求是否来自 ajax客户端request.is_ajax()
取决于客户端是否设置了X-Requested-With
header。攻击者可能会删除此 header。我再次建议您还添加 CORS 验证,这是浏览器用来防止 Django 的 CSRF 令牌之外的 CSRF 攻击的方法。这通常是使用 Django-cors-headers package
And why token authentication isn't subject to csrf attacks? It does not seem more secure to me than the session. As I see it, both of them use HTTP headers to pass a token (in token authentication is in the Authorization header, and session is a cookie which is also a header)
使用 Authorization
header 发送令牌(您也可以决定使用自定义 header 但这是互操作性的标准)而 session auth 使用由浏览器自动发送的 cookie,这就是它们容易受到 CSRF 攻击的原因。对于令牌,客户端必须显式设置 header 因此它必须知道令牌,而攻击者甚至不必知道 cookie 中存储的内容,因为浏览器会自动发送其 cookie 存储中的任何内容对于那个网站。
我已将 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 客户端和软件客户端?因此避免为令牌使用另一个单独的数据库 table。
因为我只想使用会话身份验证,如何只对 ajax 客户端实施 CSRF?
您不应该仅为 ajax 客户端启用 CSRF 保护——这没有任何意义。您如何区分 "ajax" 客户端和 "normal" 客户端?如果它会完成,例如通过一些查询参数,那么攻击者就可以使用这个 "normal" link 来做坏事。
当您使用基于令牌的身份验证时,攻击者不能仅使用通用 URL 来透明地对您的请求进行身份验证。这就是为什么只有基于会话的身份验证需要将有效的 CSRF 令牌包含在请求中。
因此出于安全原因,有 2 个选项:
- 要么使用基于会话的身份验证,但是您需要在每次请求时发送身份验证 cookie 和 CSRF 令牌;
- 或使用基于令牌的身份验证,这更简单,因为您只需要提供身份验证令牌,例如作为查询参数。
Can I use token authentication that gets the token from the standard django_session table? just use that as token?
理论上,您可以通过编写一些自定义身份验证中间件来实现这一点,这些中间件将使用查询参数中的令牌并将其与会话 table 匹配,但这通常是个坏主意。
首先,再使用一个 table 并没有那么大的开销,但是如果没有它,系统将更难阅读和维护。
其次,它也会使系统更加脆弱。由于会话和令牌是 2 个完全不同的实体,因此它们可以具有例如不同的寿命。会话可以刷新,它们的 TTL 可以比令牌 TTL shorter/longer。例如,默认的 django 会话 TTL 是 2 周。您想使远程服务器逻辑复杂化以每 2 周获取一次新令牌吗?或者想象一下令牌被泄露的情况。您是否也想强制 ajax 客户端注销?
使用令牌认证并不是必须的,只是 Session 认证容易受到 CSRF 攻击。您可以尝试使用 CORS 机制和 CSRF 令牌来防止这种情况,但它仍然不完全安全。 老实说,令牌身份验证并不完全适用于浏览器,因为如果您不使用非常复杂和精密的机制来处理令牌,则可以使用浏览器的开发人员工具轻松检索令牌。将它用于 third-party 个应用程序更简单。
虽然 CSRF 攻击只适用于浏览器(Ajax 客户端),你不应该试图排除它们,因为检查请求是否来自 ajax客户端
request.is_ajax()
取决于客户端是否设置了X-Requested-With
header。攻击者可能会删除此 header。我再次建议您还添加 CORS 验证,这是浏览器用来防止 Django 的 CSRF 令牌之外的 CSRF 攻击的方法。这通常是使用 Django-cors-headers package
And why token authentication isn't subject to csrf attacks? It does not seem more secure to me than the session. As I see it, both of them use HTTP headers to pass a token (in token authentication is in the Authorization header, and session is a cookie which is also a header)
使用 Authorization
header 发送令牌(您也可以决定使用自定义 header 但这是互操作性的标准)而 session auth 使用由浏览器自动发送的 cookie,这就是它们容易受到 CSRF 攻击的原因。对于令牌,客户端必须显式设置 header 因此它必须知道令牌,而攻击者甚至不必知道 cookie 中存储的内容,因为浏览器会自动发送其 cookie 存储中的任何内容对于那个网站。