标准情况是在 Django 中处理 HTML 表单。在表单中的模板中{% csrf_token %},它应该是注册的。任务是使用纯 JS 方法在 ajax 函数中实现一个简单的功能,即 通过对象XMLHttpRequest。要使此功能与 Django 一起使用,您需要XMLHttpRequest通过csrf_token. 令牌的值由 JS 脚本通过以下命令从站点的 cookie 中获取:
var csrfCookie = document.cookie.match(/csrftoken=([\w-]+)/);
并插入到 HTTP 请求标头中:
Request = new XMLHttpRequest();
Request.setRequestHeader("X-CSRFToken", csrfCookie);
令牌的值是正确的,但总是相同的,而模板中令牌的值总是不同的,应该是这样。因此,向服务器发送请求时会出现令牌不匹配错误。当然,令牌不匹配的问题现在已经解决了,但是通过hidden input在 Django 用于此目的的 HTML 表单中获取当前令牌的值的解决方法:
<input type="hidden" name="csrfmiddlewaretoken" value="CSRF-токен">
当前隐藏表单域token的值:
var csrfCookie = document.getElementsByName("csrfmiddlewaretoken")[0].value;
然而,原则上这个问题仍然悬而未决,因为不清楚为什么相同的 CSRF 令牌值存在于 cookie 中。顺便说一句,django 文档提供了一个 JS 脚本函数来获取这个值,并再次通过 cookie 处理。
对此有两个问题: 1.为什么在这种情况下,cookie 中的 CSRF 令牌的值不会随着 HTML 表单页面的每次更新而改变,而表单内部的令牌本身总是不同的。 2.实际上,当令牌的值可以从 cookie 或表单本身的隐藏输入中获取时,安全性在哪里?
CSRF 攻击示例(来自 Wikipedia) 攻击是通过在网页上放置链接或脚本来执行的,该网页试图访问已知(或可能)已通过身份验证的受攻击用户的站点。例如,用户 Alice 可能正在浏览另一个用户 Bob 发布消息的论坛。让 Bob 创建一个标签,其中指定 URL 作为图片的来源,当点击它时,在 Alice 的银行网站上执行一个动作,例如: Bob: Hello, Alice!看看多可爱的猫:
<img src="http://bank.example.com/withdraw?account=Alice&amount=1000000&for=Bob">如果 Alice 的银行将 Alice 的认证信息存储在 cookie 中,并且如果 cookie 还没有过期,当 Alice 尝试下载图片时,Alice 的浏览器会在请求中发送一个 cookie 向 Bob 的账户转账,这将确认 Alice 的认证。因此,交易将成功完成,尽管它的确认将在 Alice 不知情的情况下发生。换句话说,cookie 不能保证是 Alice 创建了表单。他们只验证身份,而不是数据。保护站点的典型方法是使用“密钥”,这是一个随机生成并存储在访问者会话中的特殊值。只有服务器知道,我们甚至不会向访问者展示。
1 cookie 中 CSRF 令牌的值没有变化,因为默认值为
CSRF_COOKIE_AGE31449600(1 年,以秒为单位)。表单内部的令牌本身是不同的,因为它是使用django.middleware.csrf.CsrfViewMiddleware服务器上的密钥生成的(基于cookies)。不知道密钥,就不可能生成服务器会认为正确的令牌。2只有当有人可以访问用户的计算机时,才能获取令牌的价值。但是他根本不需要CSRF,tk。有更简单的方法可以自己发送请求。
来自 Django 文档(翻译)
这个怎么运作:
CSRF 保护基于以下几点:
基于其他站点无法访问的随机秘密值的 CSRF cookie。
此 cookie 已设置
CsrfViewMiddleware。django.middleware.csrf.get_token()如果尚未在请求中设置它,则它与它调用的每个响应(内部用于获取 CSRF 令牌的函数)一起发送。为了防止 BREACH 攻击,令牌不仅仅是一个秘密;将随机盐添加到密钥中并用于对其进行加密。
出于安全原因,每次用户登录时,secret 的值都会发生变化。
csrfmiddlewaretoken所有传出的 POST 表单中都存在一个名为“”的隐藏表单字段。同样,该字段的值是添加了盐并用于对其进行加密的密钥的值。每次调用都会重新生成盐get_token(),因此表单字段的值会在每次此类响应时发生变化。这部分由模板标签完成。
对于所有不使用 HTTP GET、HEAD、OPTIONS 或 TRACE 的传入请求,必须存在 CSRF cookie 并且“
csrfmiddlewaretoken”字段必须存在且有效。如果不是,用户将收到 403 错误。在检查 "
csrfmiddlewaretoken" 字段的值时,仅将秘密而不是完整的令牌与 cookie 值中的秘密进行比较。这允许使用不断变化的令牌。尽管每个请求都可以使用自己的令牌,但秘密仍然由所有人共享。该检查正在进行中
CsrfViewMiddleware。此外,对于 HTTPS 请求,它
CsrfViewMiddleware执行严格的链接检查。这意味着即使子域可以在您的域上设置或修改 cookie,它也不能强制用户发布到您的应用程序,因为该请求不会来自您自己的确切域。这也适用于在 HTTPS 下使用与会话无关的密钥时可能发生的中间人攻击,因为即使客户端通过 HTTPS 与站点进行通信,HTTP Set-Cookie 标头也会被客户端接受(不幸的是) . 不对 HTTP 请求执行Referer 验证,因为在 HTTP 上具有Referer 标头不够可靠。)
如果设置了 CSRF_COOKIE_DOMAIN 参数,则将引用者与其进行比较。此设置支持子域。例如,CSRF_COOKIE_DOMAIN = '.example.com' 将允许来自 www.example.com 和 api.example.com 的 POST 请求。如果未设置该设置,则引用者必须与 HTTP 主机标头匹配。
可以使用
CSRF_TRUSTED_ORIGINS.这确保只有从受信任域接收的表单才能用于返回 POST 数据。
它故意忽略 GET 请求(以及在 RFC 7231#section-4.2.1 中定义为“安全”的其他请求)。这些请求不应该有潜在的危险副作用,因此使用 GET 请求攻击 CSRF 应该是无害的。RFC 7231# section-4.2.1 将 POST、PUT 和 DELETE 定义为“不安全”,所有其他方法也被认为是不安全的,以提供最大程度的保护。
CSRF 保护无法防止中间人攻击,因此请使用带有 HTTP 严格传输安全性的 HTTPS。这还假设检查 HOST 标头并且您的站点上没有任何跨站点脚本漏洞(因为 XSS 漏洞已经允许攻击者执行 CSRF 漏洞允许的所有事情,甚至更糟)。