• csrf简单说明


    csrf攻击流程

    csrftoken机制

    form表单通过csrftoken认证

    login.html文件

    <form action="/login/" method="post">
        {% csrf_token %} -- 会生成一个隐藏的input标签,value属性里面放着token值,name属性值为csrfmiddlewaretoken
        用户名: <input type="text" name="username">
        <input type="submit">
            
    </form>
    
    {% csrf_token %} 当我们使用form表单标签来发送请求时,如果需要通过csrftoken认证,那么必须将它写到我们的form表单标签里面,里面的任意位置

    校验过程解释

    html页面中的{% csrf_token %}
      <input type="hidden" name="csrfmiddlewaretoken" value="WVHKQeAuMS4RGqyLybryIBAfacDa1Dp7PEaB3Badv3y0fvLqydX36xAVen6z3oS4">
      
    cookie中的 
        csrftoken:CeFG6SA8Y8hcHAX5R93sxrS37v3iFFlcvX8xjfaRHjLlgFaKRbzXVnSJbGwHHqO9
        
    django会取出提交数据部分的token值和cookie中的token值进行如下比较:
        WVHKQeAuMS4RGqyLybryIBAfacDa1Dp7PEaB3Badv3y0fvLqydX36xAVen6z3oS4 -- 前32位可以对后面的几位进行解密,解密出以secret_key1  一个字符串
        
        CeFG6SA8Y8hcHAX5R93sxrS37v3iFFlcvX8xjfaRHjLlgFaKRbzXVnSJbGwHHqO9 -- 前32位可以对后面的几位进行解密,解密出以secret_key2  一个字符串
        
        secret_key1 = secret_key2 
        
        说明:
             token字符串的前32位是salt, 后面是加密后的token, 通过salt能解密出唯一的secret。
        django会验证表单中的token和cookie中token是否能解出同样的secret,secret一样则本次请求合法。
        
    MIDDLEWARE = [
            ...
        'django.middleware.csrf.CsrfViewMiddleware',
          ...
    ]
        
    源码
    def _compare_salted_tokens(request_csrf_token, csrf_token):
        # Assume both arguments are sanitized -- that is, strings of
        # length CSRF_TOKEN_LENGTH, all CSRF_ALLOWED_CHARS.
        return constant_time_compare(
            _unsalt_cipher_token(request_csrf_token),
            _unsalt_cipher_token(csrf_token),
        )
    
    def _unsalt_cipher_token(token):
        """
        Given a token (assumed to be a string of CSRF_ALLOWED_CHARS, of length
        CSRF_TOKEN_LENGTH, and that its first half is a salt), use it to decrypt
        the second half to produce the original secret.
        """
        salt = token[:CSRF_SECRET_LENGTH]
        token = token[CSRF_SECRET_LENGTH:]
        chars = CSRF_ALLOWED_CHARS
        pairs = zip((chars.index(x) for x in token), (chars.index(x) for x in salt))
        secret = ''.join(chars[x - y] for x, y in pairs)  # Note negative values are ok
        return secret

     

    ajax请求通过csrftoken认证

    方式1

    首先在html文件中间,写上我们的{% csrf_token %}
    
    $('#btn').click(function () {
    
            var uname = $("#uname").val();
            // 获取csrfmiddlewaretoken的input标签value属性对应的值
            var token = $('[name="csrfmiddlewaretoken"]').val();
    
            $.ajax({
                url:'/login/',
                type:'post',
                //将token值放到请求数据部分
                data:{uname:uname,csrfmiddlewaretoken:token},
                success:function (res) {
                    console.log(res);
                }
    
            })
        })

    方式2:

    使用'{{ csrf_token }}' 这个模板渲染标签,这样就不要在我们html页面中写{% csrf_token %}了。
    $('#btn').click(function () {
    
            //方式1
            var uname = $("#uname").val();
            // 直接就能得到csrfmiddlewaretoken的input标签value属性对应的值
            var token = '{{ csrf_token }}';
                    
            $.ajax({
                url:'/login/',
                type:'post',
                data:{uname:uname,csrfmiddlewaretoken:token},
                success:function (res) {
                    console.log(res);
                }
    
            })
    
        })

    方式3

    借助js操作cookie的方法来获取到cookie中的csrftoken那个键对应的值
    然后将这个值组成一个请求头,放到此次请求中
    headers:{"X-CSRFToken":这个值}
    这个值,通过js能够获取,通过jquery也能获取,我们看一下jquery如何操作cookie
    
    jquery操作cookie参考:https://www.cnblogs.com/clschao/articles/10480029.html
    下载网址:http://plugins.jquery.com/cookie/
    $('#btn').click(function () {
    
            //方式3
                  // 前提:需要在html页面中写上{% csrf_token %}或者{{ csrf_token }},不然此次获取这个html页面的时候,响应中不会有这个csrftoken的cookie值 
            var uname = $("#uname").val();
            
                  // 通过js或者jquery来获取cookie中的csrftoken这个键对应的token值
            var token = $.cookie('csrftoken');  
            $.ajax({
                url:'/login/',
                type:'post',
                  // 将获取到的token值放到请求头中,这个请求头键值对的的键必须是"X-CSRFToken"
                headers:{
                    "X-CSRFToken":token,
                },
                // django先去获取请求数据部分的token值,获取不到,就去找一个叫做X-CSRFToken请求头键值对,他的值和cookie中的csrftoken的值要相等。
                data:{uname:uname,},
                success:function (res) {
                    console.log(res);    
                }
    
            })
    
        })

    ajax上传文件

    html部分
    
    用户名: <input type="text" name="username">
    密码: <input type="text" name="password">
    头像: <input type="file" name="touxiang" >
    <button id="sub">上传</button>
    
    js部分
    $('#sub').click(function () {
    
            //ajax上传文件必须依赖于FormData对象
            var formdata = new FormData();
    
            var uname = $('[name="username"]').val();
            var pwd = $('[name="password"]').val();
                  // 获取浏览器上的文件数据方法:$('[name="touxiang"]')[0].files[0]
            var file_obj = $('[name="touxiang"]')[0].files[0];
    
            {#formdata.append('xx','oo')  //django 获取数据:post request.POST.get('xx') -- oo#}
            //request.POST
            formdata.append('uname',uname)
            formdata.append('pwd',pwd)
    {#        {% csrf_token %}#}
            formdata.append('csrfmiddlewaretoken','{{ csrf_token }}')
    
            //request.FILES
            formdata.append('touxiang',file_obj)
    
            $.ajax({
                {#url:'/upload/',#}
                url:'',  //如果路径为空,那么使用当前页面的路径,也就是往当前页面的路径下进行提交
                type:'post',
                data:formdata,
                // 下面的两个参数的意思是,不要对数据进行任何的预处理和加工
                // 固定写法
                processData:false,
                contentType:false,
    
                success:function (res) {
                    console.log(res);
    
                }
    
            })
    
        })

    views页面

    def login(request):
        if request.method ==  "GET":
            return render(request,"login.html")
        else:
            # file_obj = request.FILES.get('touxiang')
            # with open(file_obj.name,"wb") as fp:
            #     for line in file_obj:
            #         fp.write(line)
            # 方式二: chunks()可以设定传输文件时每次传送的大小
            file_obj = request.FILES.get('touxiang')
            with open(file_obj.name,"wb") as fp:
                for chunk in file_obj.chunks():
                    fp.write(chunk)
            return HttpResponse('OK')

    上传多文件

    标签写法: <input type="file" name="touxiang" multiple>
  • 相关阅读:
    后台管理UI的选择
    通过Js对电话和姓名身份证等进行部分隐藏处理
    12个用得着的JQuery代码片段
    Java获取登录用户IP地址
    Android Gson解析json详解
    Android——SD卡工具类——SDCardUtils.java
    【读书笔记】---《失控》
    【读书笔记】.Net并行编程(三)---并行集合
    Wix 安装部署教程(十六) -- 自动生成多语言文件
    【月末轻松篇】--- 那些奇葩的Bugs
  • 原文地址:https://www.cnblogs.com/fdsimin/p/13390825.html
Copyright © 2020-2023  润新知