一、什么是CSRF
CSRF, Cross Site Request Forgery, 跨站伪造请求。举例来讲,某个恶意的网站上有一个指向你的网站的链接,如果某个用户已经登录到你的网站上了,那么当这个用户点击这个恶意网站上的那个链接时,就会向你的网站发来一个请求,你的网站会以为这个请求是用户自己发来的,其实呢,这个请求是那个恶意网站伪造的。
Django为用户实现跨站请求伪造保护的功能,通过中间件 django.middleware.csrf.CsrfViewMiddleware 来完成。而对于django中设置防跨站请求伪造功能有分为全局设置和局部设置。
二、Django提供CSRF防护机制
Django第一次响应某个客户端的请求时,会在服务器端随机生成一个token,然后把这个token放到cookie中返回给客户端。然后客户端每次POST请求时都会带上这个token,这样就避免了CSRF攻击。
-
在返回的HTTP响应的cookie中,Django会添加一个csrftoken字段,值为随机生成的token
-
在POST表单中,必须包含一个csrfmiddlewaretoken隐藏字段,需要在模板中添加{% csrf_token %}自动生成
-
在处理POST请求之前,Django会验证cookie中csrftoken和表单中csrfmiddlewaretoken的值是否一致。如果一致,则表明这是一个合法请求。否则这个请求就是伪造的,返回403 Forbidden。
-
在Ajax POST请求中,添加一个"X-CSRFToken"头部,值为cookie中的csrftoken的值。
三、CSRF设置
1. 全局设置(中间件)
1
|
django.middleware.csrf.CsrfViewMiddleware
|
2. 局部设置(视图函数)
1
2
3
4
5
6
7
8
9
|
from
django.views.decorators.csrf
import
csrf_exempt,csrf_protect
@csrf_protect
# 为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置CSRF中间件。
def
func():
pass
@csrf_exempt
# 取消当前函数防跨站请求伪造功能,即便settings中设置了CSRF中间件。
def
func():
pass
|
四、应用CSRF
1. 前端Form表单中设置CSRF
1
2
3
4
|
<form method
=
"post"
>
{
%
csrf_token
%
}
...
<
/
form>
|
2. 自动在每个Ajax请求头部中添加"X-CSRFToken"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
/
/
导入jquery.cookie.js 通过$.cookie(
'csrftoken'
)获取csrf_token
/
/
beforeSend在每个Ajax请求之前自动设置请求头部
"X-CSRFToken"
<script src
=
"/static/plugin/jquery/jquery-1.8.0.js"
><
/
script>
<script src
=
"/static/plugin/jquery/jquery.cookie.js"
><
/
script>
<script
type
=
"text/javascript"
>
var csrftoken
=
$.cookie(
'csrftoken'
);
function csrfSafeMethod(method) {
/
/
these HTTP methods do
not
require CSRF protection
return
(
/
^(GET|HEAD|OPTIONS|TRACE)$
/
.test(method));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if
(!csrfSafeMethod(settings.
type
) && !this.crossDomain) {
xhr.setRequestHeader(
"X-CSRFToken"
, csrftoken);
}
}
});
<
/
script>
|
3. 单独在Ajax请求中设置"X-CSRFToken"头部
1
2
3
4
5
6
7
8
|
<script src
=
"/static/plugin/jquery/jquery-1.8.0.js"
><
/
script>
<script src
=
"/static/plugin/jquery/jquery.cookie.js"
><
/
script>
<script
type
=
"text/javascript"
>
$.ajax({
headers:{
"X-CSRFToken"
:$.cookie(
'csrftoken'
)},
...
})
<
/
script>
|