day21-CSRF

一、前言

之前我们写代码,都是会把settings配置文件里面的csrf的中间注释掉,不然我们请求post时候的会出现403 forbidden,那这个到底有啥用呐?它的原理又是什么呐?

csrf原理:

我们向服务请求时,服务器认为你是get请求的,服务器不仅把数据给你,还偷偷的的给你一大堆字符串,这个字符串是加密的,但是只有我服务器自己能反解,你客户端下一次提交数据的时候,需要带上这个字符串来再来,这样的话我服务器才会允许,不然的话,不允许你提交数据。

原理图:

二、From表单提交方式

2.1、前提条件

说明:因为我们之前都是注释掉django中的settings文件中的csrf插件,我们现在不用注释掉

'django.middleware.csrf.CsrfViewMiddleware' #全局中间件

2.2、templates中login.html的改进

说明:在输入框之前加上{% csrf_token %},表示这边加上一个隐藏的input框,这个input框默认值是csrf_token值,提交的发送给后端

<body>
    <form method="post" action="/login/">
        {% csrf_token %}  #会隐藏一个input框,这个input框的默认值为csrf_token的值
        <input type="text" name="user" placeholder="用户名">
        <input type="password" name="pwd" placeholder="密码">
        <input type="checkbox" name="rmb" value="1">10秒免登录
        <input type="submit" value="登录">
    </form>
</body>

如图:

确实会在添加一个隐藏的input的框,这个input乱的value是csrf_token的值。

2.3、get请求成cookie

说明:当我get请求的时候,我会自动在我的浏览器cookie生成一个值,然后相应的时候,服务器会返回这个cookie的值

所以,在input框之前添加{% csrf_toke %}的时候,不仅在form中生产一个隐藏的input框,而且请求get的时候,在本地cookie也会生产csrf的值,当然如果你在前端指向获取csfr_token的值,你就直接在前端获取就行了:

{{ csrf_token }}

三、ajax提交

  我们之前说了,当我们需要用post提交的时候,我们需要带这个csrf_token去后台去跟服务器去校验,那我们怎么带这个这个csrf_token值呐,其实我们在请求的时候,把它放在header里面,发送给服务器就可以了。

3.1、ajax执行前置条件

 说明:就是说对整个页面的ajax的做一个配置,如果是整体的ajax都要统一的加一个header,或者说统一的都是用post的请求方式,因为发送ajax之前都会执行以下这个函数,那么就可以用如下方式:

$.ajaxSetup({
                beforeSend:function(xhr,settings){
                    xhr.setRequestHeader('X-CSRFtoken', $.cookie('csrftoken'));
             //xhr 表示是XMLHTTPResquest的一个对象,因为ajax的发送底层原理就是用这个的 
                 //obj=XMLHTTPReuquest()  
                 //obj.open() 
                 //obj.send()
                   //settings是下面的ajax的配置,比如settings.type,settings.url,settings.data等等
                }
            });

3.2、ajax的请求方式

说明:所以我们就用完整的ajax请求一次

 1  <body>
 2     <form>
 3         <input type="text" name="user" placeholder="用户名">
 4         <input type="password" name="pwd" placeholder="密码">
 5         <input type="checkbox" name="rmb" value="1">10秒免登录
 6         <input type="submit" value="登录">
 7         <input id="btn" type="button" value="按钮">  #定义ajax请求的按钮
 8     </form>
 9     <script src="/static/jquery-1.12.4.js"></script>
10     <script src="/static/jquery.cookie.js"></script>
11     <script>
12         $(function(){
13             var csrf_token = $.cookie('csrftoken');  #从cookie中获取csrftoken的值
14             $.ajaxSetup({
15                 beforeSend:function(xhr,settings){
16                     //这边可以写成X-CSRFTOKEN,但是官方建议写成X-CSRFtoken,记住了请求头信息不能用下划线,下划线是非法的,所以只能用扛
17                     xhr.setRequestHeader('X-CSRFtoken', $.cookie('csrftoken')); 
18                     //settings是下面的ajax的配置
19                 }
20             });
21             
22             $('#btn').click(function(){
23                 $.ajax({
24                     url:'/login/',
25                     type:"POST",
26                     data:{"user":"root",'pwd':'123'},
27                     //headers:{'X-CSRFtoken':csrf_token},  //写了ajaxSetup,这边就不用写了
28                     success:function(arg){
29                         //location.href = '/index/'
30                     }
31                 })
32             })
33         })
34     </script>
35 </body>
login.html

3.3、排除post请求

说明:如果我的ajax里面不是post请求是get请求的话,那咋办,它也会照样需要发送csrf_token,但是我们只想用post请求的时候,去校验这个csrf_token值:

 function csrfSafeMethod(method) {
            // these HTTP methods do not require CSRF protection
            return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
        }

 所以我们完整的test.html编写如下:

 1 <!DOCTYPE html>
 2 <html>
 3 <head lang="en">
 4     <meta charset="UTF-8">
 5     <title></title>
 6 </head>
 7 <body>
 8     {% csrf_token %}
 9   
10     <input type="button" onclick="Do();"  value="Do it"/>
11   
12     <script src="/static/plugin/jquery/jquery-1.8.0.js"></script>
13     <script src="/static/plugin/jquery/jquery.cookie.js"></script>
14     <script type="text/javascript">
15         var csrftoken = $.cookie('csrftoken');
16   
17         function csrfSafeMethod(method) {
18             // these HTTP methods do not require CSRF protection
19             return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
20         }
21         $.ajaxSetup({
22             beforeSend: function(xhr, settings) {
23                 if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
24                     xhr.setRequestHeader("X-CSRFToken", csrftoken);
25                 }
26             }
27         });
28         function Do(){
29   
30             $.ajax({
31                 url:"/app01/test/",
32                 data:{id:1},
33                 type:'POST',
34                 success:function(data){
35                     console.log(data);
36                 }
37             });
38   
39         }
40     </script>
41 </body>
42 </html>
test.html

更多:https://docs.djangoproject.com/en/dev/ref/csrf/#ajax

三、跨站请求伪造

django为用户实现防止跨站请求伪造的功能,通过中间件 django.middleware.csrf.CsrfViewMiddleware 来完成。而对于django中设置防跨站请求伪造功能有分为全局和局部。

3.1、全局

中间件 django.middleware.csrf.CsrfViewMiddleware

3.2、局部

说明:如果你100个函数,只有两个不用,那么就不用注释掉全局的,用csrf_exempt,如果说100个函数只用两个需要认证,就需要注释掉全局的,然后用csrf_protect。

局部:

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

使用前提:from django.views.decorators.csrf import csrf_exempt,csrf_protect

3.3、具体使用如下:

from django.views.decorators.csrf import csrf_exempt,csrf_protect  #这边需要导入这两个模块

@csrf_exempt  #不需要认证
def index(request):
    if request.session.get("is_login",None):
        return render(request,'index.html')
    else:
        return HttpResponse('gun')

 

posted @ 2018-04-11 21:26  帅丶高高  阅读(193)  评论(0编辑  收藏  举报