CSRF中间件和模板标记提供了易于使用的保护 Cross Site Request Forgeries 。当恶意网站包含链接、表单按钮或一些旨在使用在其浏览器中访问恶意站点的登录用户的凭据在您的网站上执行某些操作的Java脚本时,就会发生此类攻击。文中还介绍了一种相关的攻击类型--“登录CSRF”,即攻击站点诱骗用户的浏览器使用其他用户的凭据登录到站点。
对CSRF攻击的第一个防御措施是确保GET请求(和其他安全的方法,如 RFC 9110#section-9.2.1 )是无副作用的。然后,通过POST、PUT和DELETE等不安全方法发出的请求可以通过中概述的步骤进行保护 如何使用Django的CSRF保护 。
CSRF保护基于以下内容:
作为随机保密值的CSRF Cookie,其他站点将无法访问。
CsrfViewMiddleware
将此Cookie与响应一起发送到 django.middleware.csrf.get_token()
被称为。它也可以在其他情况下发送它。出于安全原因,每次用户登录时都会更改机密的值。
一个名为‘csrfmidleware Token’的隐藏表单域,出现在所有传出的POST表单中。
为了保护自己免受 BREACH 攻击时,此字段的值不是简单的秘密。它使用掩码对每个响应进行不同的加扰。每次调用时都会随机生成掩码 get_token()
,因此每次的表单字段值都不同。
这部分由 csrf_token
模板标签。
对于所有不使用HTTP GET、HEAD、OPTIONS或TRACE的传入请求,必须存在CSRF cookie,并且“CSRFMiddleWareToken”字段必须存在且正确。否则,用户将收到403错误。
验证“csrfmiddlewaretoken”字段值时,仅将机密(而不是完整令牌)与cookie值中的机密进行比较。这允许使用不断变化的令牌。虽然每个请求都可以使用自己的令牌,但机密仍然是所有人都有的。
这张支票是由 CsrfViewMiddleware
.
CsrfViewMiddleware
验证 Origin header ,如果由浏览器提供,则针对当前主机和 CSRF_TRUSTED_ORIGINS
布景。这提供了针对跨子域攻击的保护。
此外,对于HTTPS请求,如果 Origin
未提供标头, CsrfViewMiddleware
执行严格的引用检查。这意味着即使子域可以在您的域上设置或修改Cookie,它也不能强制用户发布到您的应用程序,因为该请求不会来自您自己的确切域。
这也解决了一个中间人在使用会话独立的秘密时,在HTTPS下可能受到的攻击,因为HTTP Set-Cookie
不幸的是,客户机甚至在使用HTTPS与站点通信时也会接受报头。(没有对HTTP请求执行引用检查,因为存在 Referer
头在HTTP下不够可靠。)
如果 CSRF_COOKIE_DOMAIN
设置后,将引用者与其进行比较。您可以通过包含引导点来允许跨子域名请求。例如, CSRF_COOKIE_DOMAIN = '.example.com'
将允许来自 www.example.com
和 api.example.com
.如果未设置设置,则引用者必须与HTTP匹配 Host
标题。
将接受的引用扩展到当前主机或cookie域之外,可以使用 CSRF_TRUSTED_ORIGINS
设置。
这确保只有源自受信任域的表单才能用于回发数据。
它故意忽略GET请求(以及其他被定义为安全的请求 RFC 9110#section-9.2.1 )。这些请求应该永远不会有任何潜在的危险副作用,因此带有GET请求的CSRF攻击应该是无害的。 RFC 9110#section-9.2.1 将POST、PUT和DELETE定义为“不安全”,所有其他方法也被假定为不安全,以获得最大限度的保护。
CSRF保护无法抵御中间人攻击,因此使用 HTTPS 具有 HTTP严格传输安全 . 它也假定 validation of the HOST header 而且没有 cross-site scripting vulnerabilities 在您的站点上(因为XSS漏洞已经让攻击者做任何CSRF漏洞允许的事情,而且更糟)。
去掉 Referer
页眉
为了避免向第三方网站公开引用URL,您可能需要 disable the referer 在你的网站上 <a>
标签。例如,您可以使用 <meta name="referrer" content="no-referrer">
标记或包括 Referrer-Policy: no-referrer
标题。由于CSRF保护对HTTPS请求进行严格的引用检查,这些技术会导致使用“不安全”方法的请求出现CSRF故障。相反,使用诸如 <a rel="noreferrer" ...>"
用于链接到第三方网站。
站点内的子域将能够在客户端上为整个域设置Cookie。通过设置Cookie并使用相应的令牌,子域将能够绕过CSRF保护。避免这种情况的唯一方法是确保子域由受信任的用户控制(或者至少无法设置Cookie)。请注意,即使没有CSRF,也存在其他漏洞,例如会话固定,这使得将子域提供给不受信任方是一个坏主意,并且这些漏洞不容易使用当前的浏览器修复。
下面的示例假设您使用的是基于函数的视图。如果您使用的是基于类的视图,则可以参考 Decorating class-based views .
这个修饰器将视图标记为不受中间件所保证的保护。例子::
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def my_view(request):
return HttpResponse("Hello world")
提供保护的装饰器 CsrfViewMiddleware
到一个观点。
用法:
from django.shortcuts import render
from django.views.decorators.csrf import csrf_protect
@csrf_protect
def my_view(request):
c = {}
# ...
return render(request, "a_template.html", c)
通常 csrf_token
如果 CsrfViewMiddleware.process_view
或者类似的 csrf_protect
还没有运行。视图修饰符 requires_csrf_token
可用于确保模板标记正常工作。这个修饰符的工作原理与 csrf_protect
,但从不拒绝传入请求。
例子::
from django.shortcuts import render
from django.views.decorators.csrf import requires_csrf_token
@requires_csrf_token
def my_view(request):
c = {}
# ...
return render(request, "a_template.html", c)
此修饰符强制视图发送CSRF cookie。
许多设置可用于控制Django的CSRF行为:
不,这是设计的。不将CSRF保护链接到会话允许在诸如 pastebin 允许没有会话的匿名用户提交。
如果要在用户会话中存储CSRF令牌,请使用 CSRF_USE_SESSIONS
设置。
出于安全原因,每次用户登录时都会旋转CSRF令牌。登录前生成表单的任何页面都将具有旧的、无效的CSRF令牌,需要重新加载。如果用户在登录后使用“后退”按钮或登录到其他浏览器选项卡,则可能会发生这种情况。
7月 22, 2024