? CSRF(Cross-site request forgery)跨站请求伪造,也被称为“One Click Attack”或者Session Riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。尽管听起来像跨站脚本(XSS),但它与XSS非常不同,XSS利用站点内的信任用户,而CSRF则通过伪装成受信任用户的请求来利用受信任的网站。与XSS攻击相比,CSRF攻击往往不大流行(因此对其进行防范的资源也相当稀少)和难以防范,所以被认为比XSS更具危险性。
? django 第一次响应来自某个客户端的请求时,会在服务器端随机生成一个 csrftoken值,把这个 csrftoken 放在 cookie 里。然后每次请求都带着这个值过来完成校验。
token字符串的前32位是salt, 后面是加密后的token, 通过salt能解密出唯一的secret。官方文档中说到,检验token时,只比较secret是否和cookie中的secret值一样,
而不是比较整个token。django会验证表单中的token和cookie中token是否能解出同样的secret,secret一样则本次请求合法,这样就能避免被 CSRF 攻击。
? 例如:在html 中, 为每个post请求的form 表单增加一个 {% csrf_token %} 标签,它的功能其实是给form表单增加一个隐藏的input标签。服务端收到请求后,
django 会对这个请求的 cookie 里的 csrftoken 字段的值和提交的表单里的 csrfmiddlewaretoken 字段的值进行处理,比较secret是否一样,secret一样则本次请求合法。
django通过中间件 django.middleware.csrf.CsrfViewMiddleware 来防止跨站请求伪造。
#settings.py
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',#csrf的认证
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
#为每个post请求的form 表单增加一个 {% csrf_token %} 标签,如果不添加,post请求的时候你会发现一个 Forbidden的错误
<form action="" method="post" id="loginForm" novalidate="novalidate">
{% csrf_token %}#
<div>
<input type="text" name="username" class="username" placeholder="用户名" autocomplete="off">
</div>
<div>
<input type="password" name="password" class="password" placeholder="密码" oncontextmenu="return false"
onpaste="return false">
</div>
<button id="submit" type="submit">登 陆</button>
<span style="color: red;">{{ error }}</span>
</form>
通过获取隐藏的input标签中的csrfmiddlewaretoken值,放置在data中发送。
data:{
csrfmiddlewaretoken:$("[name='csrfmiddlewaretoken']").val(), #form表单里必须写{% csrf_token %}#}
},
data:{
csrfmiddlewaretoken:"{{ csrf_token }}", #form表单里不用写{% csrf_token %} 模板语法替换产生
},
#示例:
<script src="{% static 'jquery.js' %}"></script>
#基于jQuery的实现
<script>
$('#btn').click(function () {
$.ajax({
url:"{% url 'login' %}",
type:'post' ,
data:{
username:$('[name=username]').val(),
password:$('[name=password]').val(),
csrfmiddlewaretoken:$('[name=csrfmiddlewaretoken]').val(),#form表单里必须写 {% csrf_token %}#}--方式1
#或
csrfmiddlewaretoken:"{{ csrf_token }}", #form表单里不用写 {% csrf_token %}--方式2
},
success:function(res){
var resStr = JOSN.parse(res);
console.log(res,typeof res);
}
})
})
</script>
注意:需要引入一个jquery.cookie.js插件,jquery操作cookie。下载地址 https://plugins.jquery.com/cookie/
jquery.cookie.js基于jquery;先引入jquery,再引入:jquery.cookie.js;
<script src="{% static 'jquery.js' %}"></script>
<script src="{% static 'jquery.cookie.js' %}"></script>
$.ajax({
url:'/test/',
type:'post',
headers:{"X-CSRFToken":$.cookie('csrftoken')}, #从Cookie取csrftoken,并设置到请求头headers中
#ajax里面的headers参数,自定制请求头,可以将csrf_token加在这里,我们发contenttype类型数据的时候,csrf_token就可以这样加
})
注意:
1.如果使用从cookie中取csrftoken的方式,需要确保cookie存在csrftoken值。
2.如果你的视图渲染的HTML文件中没有包含 {% csrf_token %},Django可能不会设置CSRFtoken的cookie。-->不是所有请求都有csrftoken这个cookie键值对
3.这个时候需要使用ensure_csrf_cookie()装饰器强制设置Cookie。
django.views.decorators.csrf import ensure_csrf_cookie
@ensure_csrf_cookie #强制给请求对应的响应添加csrftoken这个cookie键值对
def login(request):
pass
from django.views.decorators.csrf import csrf_exempt,csrf_protect
csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置csrfToken全局中间件。
csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。
示例1:
#views.py
from django.views.decorators.csrf import csrf_exempt, csrf_protect
# @csrf_exempt
@csrf_protect
def login(request):
if request.method == 'GET':
return render(request,'login.html')
else:
username = request.POST.get('username')
password = request.POST.get('password')
if username == 'zhangsan' and password == '1234':
return HttpResponse('OK')
else:
return redirect('login')
#login.html
<form action="/login/" method="post">
用户名: <input type="text" name="username">
密码: <input type="password" name="password">
<input type="submit">
</form>
#settings.py
MIDDLEWARE = [
'django.middleware.csrf.CsrfViewMiddleware',
]
【1】settings中设置了全局中间件,在login.html中不设置{% csrf_token %},当post提交数据时,Forbidden (403)
如果在FBV的函数上使用csrf_exempt装饰器,可以成功提交数据。
【2】settings中没有设置全局中间件,当post提交数据时可以成功提交。如果在FBV的函数上使用csrf_exempt装饰器,Forbidden (403)。
示例2:注意csrf-token装饰器的特殊性,在CBV模式下它只能加在dispatch上面。
添加装饰器的格式必须为@method_decorator(),括号里面为装饰器的函数名
from django.views.decorators.csrf import csrf_exempt, csrf_protect
from django.utils.decorators import method_decorator
#@method_decorator(csrf_exempt, name='dispatch')
class HomeView(View):
@method_decorator(csrf_exempt)
def dispatch(self, request, *args, **kwargs):
return super(HomeView, self).dispatch(request, *args, **kwargs)
def get(self, request):
return render(request, "home.html")
def post(self, request):
print("Home Viw POST method...")
return redirect("/index/")
原文:https://www.cnblogs.com/xiaomage666/p/11312682.html