要在您的视图中利用CSRF保护,请执行以下步骤:
默认情况下,CSRF中间件在 MIDDLEWARE
布景。如果覆盖该设置,请记住 'django.middleware.csrf.CsrfViewMiddleware'
应该放在任何假定CSRF攻击已经得到处理的视图中间件之前。
如果您禁用了它(不推荐),则可以使用 csrf_protect()
在您想要保护的特定视图上(见下文)。
在任何使用POST表单的模板中,使用 csrf_token
标记内的 <form>
元素,如果表单用于内部URL,例如:
<form method="post">{% csrf_token %}
不应对以外部URL为目标的POST表单执行此操作,因为这会导致CSRF令牌泄漏,从而导致漏洞。
在相应的视图函数中,确保 RequestContext
用于呈现响应,以便 {% csrf_token %}
将正常工作。如果您正在使用 render()
函数、通用视图或构造性应用程序,因为这些都使用了 RequestContext
。
虽然上面的方法可以用于AJAX POST请求,但它有一些不便之处:您必须记住将CSRF令牌作为POST数据传递给每个POST请求。因此,还有一种替代方法:在每个XMLHttpRequest上,设置一个定制 X-CSRFToken
标头(由 CSRF_HEADER_NAME
设置)设置为CSRF令牌的值。这通常更容易,因为许多JavaScript框架提供了允许在每个请求上设置标头的挂钩。
首先,您必须获得CSRF令牌。如何做到这一点取决于 CSRF_USE_SESSIONS
和 CSRF_COOKIE_HTTPONLY
设置已启用。
最后,您需要在您的AJAX请求上设置头。使用 fetch() 接口:
const request = new Request(
/* URL */,
{
method: 'POST',
headers: {'X-CSRFToken': csrftoken},
mode: 'same-origin' // Do not send CSRF token to another domain.
}
);
fetch(request).then(function(response) {
// ...
});
姜戈的 Jinja2
模板后端添加 {{ csrf_input }}
添加到所有模板的上下文中,它等同于 {% csrf_token %}
用Django模板语言编写。例如:
<form method="post">{{ csrf_input }}
而不是添加 CsrfViewMiddleware
作为全面保护,您可以使用 csrf_protect()
在需要保护的特定视图上,它具有完全相同的功能。它必须被使用 both 在输出中插入CSRF标记的视图,以及接受POST表单数据的视图。(这些通常是相同的查看功能,但并不总是)。
单独使用装饰器本身是 not recommended ,因为如果你忘记使用它,你会有一个安全漏洞。同时使用“腰带和支架”的策略很好,而且只会产生最少的开销。
默认情况下,如果传入请求未通过由执行的检查,则会向用户发送‘403禁止’响应 CsrfViewMiddleware
。通常只有当存在真正的跨站点请求伪造时,或者由于编程错误,CSRF令牌未包含在POST表单中时,才会出现这种情况。
但是,错误页不是很友好,因此您可能希望提供您自己的视图来处理这种情况。为此,请将 CSRF_FAILURE_VIEW
布景。
CSRF故障将作为警告记录到 django.security.csrf 伐木者。
如果 csrf_token
模板标记由模板使用(或 get_token
函数以某种其他方式调用), CsrfViewMiddleware
将添加一个Cookie和一个 Vary: Cookie
响应的标头。这意味着如果按照指令使用中间件,中间件将与缓存中间件配合得很好 (UpdateCacheMiddleware
优先于所有其他中间件)。
然而,如果您在各个视图上使用缓存修饰符,CSRF中间件将还不能设置Variable标头或CSRF cookie,并且响应将被缓存,而没有这两者。在这种情况下,在任何需要插入CSRF令牌的视图上,您都应该使用 django.views.decorators.csrf.csrf_protect()
装饰者优先::
from django.views.decorators.cache import cache_page
from django.views.decorators.csrf import csrf_protect
@cache_page(60 * 15)
@csrf_protect
def my_view(request): ...
如果您使用的是基于类的视图,可以参考 Decorating class-based views 。
这个 CsrfViewMiddleware
这通常是测试视图功能的一大障碍,因为需要CSRF令牌,它必须与每个POST请求一起发送。出于这个原因,Django的用于测试的HTTP客户端已经被修改为在请求上设置一个标志,从而放松中间件和 csrf_protect
这样他们就不再拒绝请求了。在所有其他方面(例如,发送Cookie等),它们的行为是相同的。
如果,出于某种原因,你 want 要执行CSRF检查的测试客户端,您可以创建强制执行CSRF检查的测试客户端的实例:
>>> from django.test import Client
>>> csrf_client = Client(enforce_csrf_checks=True)
某些视图可能具有不寻常的要求,这意味着它们不符合这里设想的正常模式。在这些情况下,许多实用程序可能会很有用。下一节描述了可能需要它们的场景。
大多数视图需要CSRF保护,但少数视图不需要。
解决方案:而不是禁用中间件并应用 csrf_protect
对于所有需要它的视图,启用中间件并使用 csrf_exempt()
。
CsrfViewMiddleware.process_view()
未使用¶在某些情况下, CsrfViewMiddleware.process_view
在您的视图运行之前可能没有运行过--例如,404和500个处理程序--但是您仍然需要表单中的CSRF令牌。
解决方案:使用 requires_csrf_token()
可能有一些不受保护的视图已被豁免 csrf_exempt
,但仍需要包括CSRF令牌。
解决方案:使用 csrf_exempt()
紧随其后的是 requires_csrf_token()
。(即 requires_csrf_token
应该是最里面的装饰者)。
一个视图只在一组条件下需要CSRF保护,并且不能在其余时间拥有它。
解决方案:使用 csrf_exempt()
对于整个视图函数,以及 csrf_protect()
因为它里面的路径需要保护。示例::
from django.views.decorators.csrf import csrf_exempt, csrf_protect
@csrf_exempt
def my_view(request):
@csrf_protect
def protected_path(request):
do_something()
if some_condition():
return protected_path(request)
else:
do_something_else()
页面通过AJAX发出POST请求,并且该页面没有带有 csrf_token
这将导致发送所需的CSRF cookie。
解决方案:使用 ensure_csrf_cookie()
在发送页面的视图上。
因为开发人员可以关闭 CsrfViewMiddleware
,Conrib应用程序中的所有相关视图都使用 csrf_protect
装饰器,以确保这些应用程序在CSRF环境下的安全性。建议希望获得相同保证的其他可重用应用程序的开发人员也使用 csrf_protect
装饰师在他们的视野中。
7月 22, 2024