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更具危险性。

2.Django下的CSRF认证机制

​ 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 来防止跨站请求伪造。

扫描二维码关注公众号,回复: 6968056 查看本文章
#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

  #为每个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>

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 %}  模板语法替换产生

    },
        

#示例:
 <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>
方式3:通过获取返回的cookie中的字符串,放置在请求头中发送。
注意:需要引入一个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

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
<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/")

猜你喜欢

转载自www.cnblogs.com/guido-van-rossum/p/11312686.html
今日推荐