浏览器在发送请求的时候,会自动带上当前域名对应的cookie内容,发送给服务端,无论这个请求是来源A网站仍是其它网站,只要请求的是A网站的连接,就会带上A网站的cookie。浏览器的同源策略并不能阻止CSRF攻击,由于浏览器不会中止js发送请求到服务端,只是在必要的时候拦截了响应的内容。或者说浏览器收到响应以前它不知道该不应拒绝。css
用户登录A网站后,攻击者本身开发一个B网站,这个网站会经过js请求A网站,好比用户点击了某个按钮,就触发了js的执行。html
攻击者是利用cookie随着http请求发送的特性来攻击。但攻击者不知道 cookie里面是什么。前端
Django中是在表单中加一个隐藏的 csrfmiddlewaretoken,在提交表单的时候,会有 cookie 中的内容作比对,一致则认为正常,不一致则认为是攻击。因为每一个用户的 token 不同,B网站上的js代码没法猜出token内容,对比必然失败,因此能够起到防范做用。jquery
和上面的相似,但不使用 cookie,服务端的数据库中保存一个 session_csrftoken,表单提交后,将表单中的 token 和 session 中的对比,若是不一致则是攻击。ajax
这个方法实施起来并不困难,但它更安全一些,由于网站即便有 xss 攻击,也不会有泄露token的问题。数据库
Django使用CsrfViewMiddleware中间件进行CSRF校验,默认开启防止csrf(跨站点请求伪造)攻击,在post请求时,没有携带csrf字段,致使校验失败,报403错误。那么咱们如何解决这种403错误呢?django
注释掉此段代码便可,可是不推荐此方式,将致使咱们的网站彻底没法防止CSRF攻击。后端
<form enctype="multipart/form-data" method="post" action="{% url 'add_data' %}">
{% csrf_token %}
</form>复制代码
必定要注意后端使用render而不要使用rendertoresponse进行渲染,这样前端就会有csrf_token变量,前端cookies中也会出现csrftoken数据,而后在HTML中使用便可。这种方式只限制在form表单中使用,ajax请求不支持。浏览器
能够只针对指定的路由去掉CSRF校验,这也分为两种状况:安全
# 导入,可使这次请求忽略csrf校验
from django.views.decorators.csrf import csrf_exempt
# 在处理函数加此装饰器便可
@csrf_exempt
def add_data(request):
result = {}
# TODO
return HttpResponse(result)复制代码
from django.views import View
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
class IndexView(View):
@method_decorator(csrf_exempt)
def dispatch(self, request, *args, **kwargs):
return super().dispatch(request, *args, **kwargs)
def get(self, request, *args, **kwargs):
return render(request, 'home.html')
def post(self, request, *args, **kwargs):
data = request.POST.get('data')
qr_path = gen_qrcode(data)
return HttpResponse(qr_path)复制代码
或者用下面的方式,把装饰器放在类外面
from django.views import View
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
@method_decorator(csrf_exempt, name='dispatch')
class IndexView(View):
def get(self, request, *args, **kwargs):
return render(request, 'home.html')
def post(self, request, *args, **kwargs):
data = request.POST.get('data')
qr_path = gen_qrcode(data)
return HttpResponse(qr_path)复制代码
以上方式都有限制,适用范围比较窄,咱们须要一种能够一劳永逸的方式:让全部请求都携带csrf数据。由于咱们是使用Django模板渲染前端页面的,因此通常会先定义一个base.html,其余页面经过{% extends "base.html" %}来引入使用,那么在base.html中添加ajax的全局钩子,在请求时添加csrf数据便可。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>{% block title %}首页{% endblock %}</title>
<link rel="stylesheet" href="{% static 'css/base.css'%}">
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
<script>
$.ajaxSetup({
data: {
csrfmiddlewaretoken: '{{ csrf_token }}'
}
})
</script>
{% block css %}
{% endblock %}
</head>
<body>复制代码
若是你以为个人文章还能够,能够关注个人微信公众号,查看更多实战文章:Python爬虫实战之路也能够扫描下面二维码,添加个人微信公众号