Django中与CSRF相关的内容

Django中与CSRF相关的内容

1.什么是CSRF?

​ CSRF(Cross-site request forgery)跨站请求伪造,也被称为“One Click Attack”或者Session Riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。尽管听起来像跨站脚本(XSS),但它与XSS非常不同,XSS利用站点内的信任用户,而CSRF则通过伪装成受信任用户的请求来利用受信任的网站。与XSS攻击相比,CSRF攻击往往不大流行(因此对其进行防范的资源也相当稀少)和难以防范,所以被认为比XSS更具危险性。

Django中与CSRF相关的内容_第1张图片

2.Django下的CSRF认证机制

Django中与CSRF相关的内容_第2张图片

Django中与CSRF相关的内容_第3张图片

Django中与CSRF相关的内容_第4张图片

​ 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一样则本次请求合法。

3.具体的实现方法

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',
]

3-1 form表单当中附加csrftoken

Django中与CSRF相关的内容_第5张图片

  #为每个post请求的form 表单增加一个 {% csrf_token %} 标签,如果不添加,post请求的时候你会发现一个 Forbidden的错误
    
    
{% csrf_token %}#
{{ error }}

3-2 Ajax的post请求设置csrf_token的方式

方式1:
    通过获取隐藏的input标签中的csrfmiddlewaretoken值,放置在data中发送。
    
    data:{
        
        csrfmiddlewaretoken:$("[name='csrfmiddlewaretoken']").val(), #form表单里必须写{% csrf_token %}#}

    },
方式2:
 data:{
       
        csrfmiddlewaretoken:"{{ csrf_token }}", #form表单里不用写{% csrf_token %}  模板语法替换产生

    },
        

#示例:
 
    
    #基于jQuery的实现
    
方式3:通过获取返回的cookie中的字符串,放置在请求头中发送。
注意:需要引入一个jquery.cookie.js插件,jquery操作cookie。下载地址 https://plugins.jquery.com/cookie/
    
    jquery.cookie.js基于jquery;先引入jquery,再引入:jquery.cookie.js;




$.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

3-3 CSRF Token相关装饰器

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
用户名: 密码:
#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/")

你可能感兴趣的:(Django中与CSRF相关的内容)