zoukankan      html  css  js  c++  java
  • Day22-CSRF跨站请求伪造

     csrf 跨站请求伪造

    一、简介

    django为用户实现防止跨站请求伪造的功能,通过中间件 django.middleware.csrf.CsrfViewMiddleware 来完成。

    1.1 第1次来访问的时候(get方法),先拿到字符串;下次再来访问的时候(post方法)也必须带着这一串字符串才能成功。CSRF是指提交数据的时候必须通过验证。cookie和session是关于用户名/密码保存的。

    第2种方法

    form表单提交的时候,加上它就可以了。

    这个CSRF字符串不仅在表单里面有了,在cookie里面也有了。

    当用form表单提交的时候,把随机字符串和cookie值都发过去了。

    1.2 如果用Ajax往后台发数据的时候,只需要把cookie值拿到,放到请求头里面发过去就可以了。

    先来看一个没有加cookie值的Ajax请求过程:

    login.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <form action="/login/" method="POST" >
            {%csrf_token%}
            <input type="text" name="user" placeholder="user"/>
            <input type="text" name="pwd" placeholder="pwd"/>
            <input type="checkbox" name="remember" value="1"/> 10秒免登录
            <input type="submit" value="提交"/>
            <input id="btn" type="button" value="按钮"/>
        </form>
        <script src="/static/jquery-1.12.4.js"></script>
        <script src="/static/jquery.cookie.js"></script>
        <script>
            $(function(){
                $('#btn').click(function(){
                    $.ajax({
                        url:'/login/',
                        type:"POST",
                        data:{'user':'root','pwd':'123'},
                        success:function(arg){
    
                        }
    
                    })
    
                })
    
            })
        </script>
    </body>
    </html>
    

     此时如果登录的话,则通不过CSRF验证,报403错误。做这个实例的时候,不要在setting里面注释这句

    'django.middleware.csrf.CsrfViewMiddleware'

     

    带上随机字符串的话, 才能登录成功。从cookie里面先把随机字符串获取到。获取方法如下:$.cookie('csrftoken')

     但是后台需要通过key去获取这个值,那么这个值对应的key是什么呢?通过打印settings.CSRF_HEADER_NAME可知,

    key是HTTP_X_CSRFTOKEN, HTTP_ 是django自动给加上的,所以我们发送的时候,只需要把key设置成 X_CSRFTOKEN就可以了。 

    由于请求头里面不能出现下划线,所以最终设置的时候应该写成 X-CSRFTOKEN。

    (1) 下面的图说明key是啥样的

    (2)下面这个例子来验证HTTP_是Django自动添加的。

    (3)理论上我们把请求头设置成X_CSRFTOKEN 就可以了。 但是由于Django有要求,请求头里面不能出现下划线,所以最终我们把请求头设置成X-CSRFTOKEN 的样子。按照官网推荐,建议写成

    X-CSRFtoken。

    headers:{'X-CSRFtoken':$.cookie('csrftoken')},

    login.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <form action="/login/" method="POST" >
            {%csrf_token%}
            <input type="text" name="user" placeholder="user"/>
            <input type="text" name="pwd" placeholder="pwd"/>
            <input type="checkbox" name="remember" value="1"/> 10秒免登录
            <input type="submit" value="提交"/>
            <input id="btn" type="button" value="按钮"/>
        </form>
        <script src="/static/jquery-1.12.4.js"></script>
        <script src="/static/jquery.cookie.js"></script>
        <script>
            $(function(){
                $('#btn').click(function(){
                    $.ajax({
                        url:'/login/',
                        type:"POST",
                        data:{'user':'root','pwd':'123'},
                        headers:{'X-CSRFtoken':$.cookie('csrftoken')},
                        success:function(arg){
    
                        }
    
                    })
    
                })
    
            })
        </script>
    </body>
    </html>
    

     此时可以用Ajax提交可以成功

    1.3  Form表单提交与Ajax方法提交的不同之处在于,去不同的地方拿csrf_token

     在 Ajax中写headers太麻烦了,可以用setup 对整个页面中所有的Ajax操作做一个配置。

    表示在发送ajax之前,会先执行一下那个函数。

    xhr是XMLHttpRequest 对象,所有的ajax操作底层用的都是它。

     

    login.html--------示例中有2个Ajax

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <form action="/login/" method="POST" >
            {%csrf_token%}
            <input type="text" name="user" placeholder="user"/>
            <input type="text" name="pwd" placeholder="pwd"/>
            <input type="checkbox" name="remember" value="1"/> 10秒免登录
            <input type="submit" value="提交"/>
            <input id="btn1" type="button" value="按钮1"/>
            <input id="btn2" type="button" value="按钮2"/>
        </form>
        <script src="/static/jquery-1.12.4.js"></script>
        <script src="/static/jquery.cookie.js"></script>
        <script>
            $(function(){
                $.ajaxSetup({
                   beforeSend:function(xhr,settings){
                       xhr.setRequestHeader('X-CSRFtoken',$.cookie('csrftoken'));
                   }
                });
                $('#btn1').click(function(){
                    $.ajax({
                        url:'/login/',
                        type:"POST",
                        data:{'user':'root','pwd':'123'},
                        //headers:{'X-CSRFtoken':$.cookie('csrftoken')},
                        success:function(arg){
    
                        }
                    })
                });
                $('#btn2').click(function(){
                    $.ajax({
                        url:'/login/',
                        type:"POST",
                        data:{'user':'root','pwd':'123'},
                        //headers:{'X-CSRFtoken':$.cookie('csrftoken')},
                        success:function(arg){
    
                        }
                    })
                })
            })
        </script>
    </body>
    </html>
    

    运行效果:两个Ajax都可以成功提交

    程序摘录

    login.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <form action="/login/" method="POST" >
            {%csrf_token%}
            <input type="text" name="user" placeholder="user"/>
            <input type="text" name="pwd" placeholder="pwd"/>
            <input type="checkbox" name="remember" value="1"/> 10秒免登录
            <input type="submit" value="提交"/>
            <input id="btn1" type="button" value="按钮1"/>
            <input id="btn2" type="button" value="按钮2"/>
        </form>
        <script src="/static/jquery-1.12.4.js"></script>
        <script src="/static/jquery.cookie.js"></script>
        <script>
            $(function(){
                $.ajaxSetup({
                   beforeSend:function(xhr,settings){
                       xhr.setRequestHeader('X-CSRFtoken',$.cookie('csrftoken'));
                   }
                });
                $('#btn1').click(function(){
                    $.ajax({
                        url:'/login/',
                        type:"POST",
                        data:{'user':'root','pwd':'123'},
                        //headers:{'X-CSRFtoken':$.cookie('csrftoken')},
                        success:function(arg){
    
                        }
                    })
                });
                $('#btn2').click(function(){
                    $.ajax({
                        url:'/login/',
                        type:"POST",
                        data:{'user':'root','pwd':'123'},
                        //headers:{'X-CSRFtoken':$.cookie('csrftoken')},
                        success:function(arg){
    
                        }
                    })
                })
            })
        </script>
    </body>
    </html>
    

     index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <h1>欢迎登录:{{username}},{{request.session.username}}</h1>
        <a href="/logout/">注销</a>
    </body>
    </html>
    

     views.py

    from django.shortcuts import render,HttpResponse,redirect
    # Create your views here.
    def login(request):
        if request.method=='GET':
            return render(request,'login.html')
        elif request.method=='POST':
            user=request.POST.get('user')
            pwd=request.POST.get('pwd')
            if user=='root' and pwd=='123':
                #生成随机字符串,写到浏览器cookie中,保存在session中。在随机字符串对应的字典中设置相关内容...
                # 在session里面设置值
                request.session['username']=user
                request.session['is_login']=True
                if request.POST.get('remember',None)=='1':
                    #设置超时时间
                    request.session.set_expiry(10)
                return redirect('/index/')
            else:
                return render(request,'login.html')
    def index(request):
        #获取当前用户的随机字符串
        #根据随机字符串获取对应的信息
        #去session中获取值,如果登录成功,显示用户名
        if request.session.get('is_login',None):
            #return HttpResponse(request.session['username'])
            return render(request,'index.html',{'username':request.session['username']})
        else:
            return HttpResponse('滚')
    def logout(request):
        request.session.clear()
        return redirect('/login/')
    

     urls.py

    from django.conf.urls import url
    from django.contrib import admin
    from app01 import views
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^login/$', views.login),
        url(r'^index/$', views.index),
        url(r'^logout/$', views.logout),
    ]
    

    二,而对于django中设置防跨站请求伪造功能有分为全局和局部。

    全局:

      中间件 django.middleware.csrf.CsrfViewMiddleware

    局部:

    注:from django.views.decorators.csrf import csrf_exempt,csrf_protect

    • @csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。
    • @csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。

    csrf_exempt

    csrf_protect

    settings会得到Ajax中的所有数据

  • 相关阅读:
    面向对象
    通信编程
    系统编程和单片机编程思维的改变
    代码是设计出来的
    好的代码设计
    通信传输协议数据包的独门绝技使用-----------共用体的使用
    $|^|z||/a|/l
    eubacteria|endosymbiosis|基因转移
    ctDNA|endosymbiosis
    mtDNA|ctDNA|cpDNA|
  • 原文地址:https://www.cnblogs.com/momo8238/p/7716832.html
Copyright © 2011-2022 走看看