跨站请求伪造(csrf)

跨站请求伪造(csrf)

一、钓鱼网站

什么是xxx
为什么要有xxx
如何使用xxx

钓鱼网站:就类似于你搭建了一个跟银行一模一样的web页面, 用户在你的网站转账的时候输入用户名 密码 对方账户, 银行里面的钱确实少了 但是发现收款人变了

原理: 你写的form表单中 用户的用户名 密码都会真实的提交给银行后台, 但是收款人的账户却不是用户填的 你暴露给用户的是一个没有name属性的input框,你自己提前写好了一个隐藏的带有name和value的input框

解决钓鱼网站的策略: 只要是用户想要提交post请求的页面 我在返回给用户的时候就提前设置好一个随机字符串, 当用户提交post请求的时候 我会自动先取查找是否有该随机字符串 , 如果有 正常提交, 如果没有 直接报403

二、csrf

2.1 在form表单中实现

在form表单中添加: {% csrf_token %}

<!--login.html-->
<body>
<form action="" method="post">
    {% csrf_token %}
    <p>
        用户: <input type="text" name="username">
    </p>
    <p>
        密码: <input type="password" name="password">
    </p>
    <p>
        <input type="submit" value="提交">
    </p>
</form>

页面展示

img

对应的中间件:django.middleware.csrf.CsrfViewMiddleware

# 对应的中间件
'django.middleware.csrf.CsrfViewMiddleware',

2.2 AJAX请求实现

方式一:

<!--login.html-->
<body>
<form action="" method="post">
    {% csrf_token %}
	<!--通过js找到这个隐藏的框-->
</form>
<button id="b1">发ajax</button>
<script>
    $('#b1').click(function () {
        $.ajax({
            url: "",
            type: "post",
            // 第一种方式
            data: {
                "username": "randy",
                "password": 123,
                "csrfmiddlewaretoken": $("[name = 'csrfmiddlewaretoken']").val()  // 使用JQuery取出csrfmiddlewaretoken的值,拼接到data中
            },
            {#data:{'username':'randy','csrfmiddlewaretoken':'{{ csrf_token }}'},#}
            {#data:{'username':'randy'},#}
            success: function (data) {
                alert(data)
            }
        })
    })
</script>

方式二:

<button id="b1">发ajax</button>

{#<script src="/static/setup.js"></script>#}
<script>
    $('#b1').click(function () {
        $.ajax({
            url:"",
            type:"post",
            // 第二种方式
            data:{'username':'randy','csrfmiddlewaretoken':'{{ csrf_token }}'},         
            success:function (data) {
                alert(data)
            }
        })
    })
</script>

方式三(引入js):

# stupe.js
function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = jQuery.trim(cookies[i]);
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) === (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}
var csrftoken = getCookie('csrftoken');



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

$.ajaxSetup({
  beforeSend: function (xhr, settings) {
    if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
      xhr.setRequestHeader("X-CSRFToken", csrftoken);
    }
  }
});
<!--login.html-->
<script src="/static/setup.js"></script>
<script>
    $('#b1').click(function () {
        $.ajax({
            url:"",
            type:"post",
            // 第三种方式           
            data:{'username':'randy'},
            success:function (data) {
                alert(data)
            }
        })
    })
</script>

三、装饰器实现(csrf)

<body>
<form action="crsf_cbv" method="post">
    {#        {% csrf_token %}#}
    <p>
        用户: <input type="text" name="username">
    </p>
    <p>
        密码: <input type="password" name="password">

    </p>
    <p>
        <input type="submit" value="提交">
    </p>

</form>
</body>
MIDDLEWARE = [   
 'django.middleware.security.SecurityMiddleware',  
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',    'django.contrib.auth.middleware.AuthenticationMiddleware',    'django.contrib.messages.middleware.MessageMiddleware',    'django.middleware.clickjacking.XFrameOptionsMiddleware',  
 # 'app.mymiddleware.my_middleware.M1',    
 # 'app.mymiddleware.my_middleware.M2',
 ]

3.1 csrf_exempt不进行校验

# urls.py
from app import views
urlpatterns = [   
    url(r'^exem/', views.exem),
]

# views.py
from django.views.decorators.csrf import csrf_exempt, csrf_protect
from django.utils.decorators import method_decorator
@csrf_exempt
def exem(request):
    """前端不需要csrf字符串验证 {% csrf_token %} """
    return HttpResponse("exempt不进行校验")

img

3.2 csrf_protect进行校验

# urls.py
from app import views
urlpatterns = [   
    url(r'^protect/', views.protect),
]

# views.py
from django.views.decorators.csrf import csrf_exempt, csrf_protect
from django.utils.decorators import method_decorator
@csrf_protect
def protect(request):
    """"""前端需要 csrf 字符串验证{% csrf_token %} """"""
    return HttpResponse("protect 校验")

img

3.3 给CBV添加csrf校验装饰器

<body>
<form action="crsf_cbv" method="post">
    {#        {% csrf_token %}#}
    <p>
        用户: <input type="text" name="username">
    </p>
    <p>
        密码: <input type="password" name="password">

    </p>
    <p>
        <input type="submit" value="提交">
    </p>

</form>
</body>

不需要验证

# urls.py
urlpatterns = [
    url(r'^crsf_cbv/', views.MyCrsfCbv.as_view()),
]

# views.py
from django.views.decorators.csrf import csrf_exempt, csrf_protect
from django.utils.decorators import method_decorator
from django.views import View
# post不验证不需要csrf字符串
class MyCrsfCbv(View):
    def get(self, request):
        return HttpResponse('hahaha')

    def post(self, request):
        return HttpResponse('post')

结果post

需要验证

方式一:

# urls.py
urlpatterns = [
    url(r'^crsf_cbv/', views.MyCrsfCbv.as_view()),
]

# views.py
# 导入模块
# method_decorator(装饰器,方法名)
from django.views.decorators.csrf import csrf_exempt, csrf_protect
from django.utils.decorators import method_decorator

from django.views import View
# 第一种方式验证,改变装饰第一个参数进行验证或不验证

# cbv装csrf_exempt装饰器,只能给dispatch添加校验
# @method_decorator(csrf_exempt,name='dispatch')

# cbv装csrf_protect,指明道姓的给谁添加校验csrf,name=get/post
@method_decorator(csrf_protect, name='post')
class MyCrsfCbv(View):
    def get(self, request):
        return HttpResponse('hahaha')

    @method_decorator(csrf_protect) # 有无
    def post(self, request):
        return HttpResponse('post')

方式二:

# urls.py
urlpatterns = [
    url(r'^crsf_cbv/', views.MyCrsfCbv.as_view()),
]

# views.py
from django.views.decorators.csrf import csrf_exempt, csrf_protect
from django.utils.decorators import method_decorator
from django.views import View

class MyCrsfCbv(View):
     # 第二种
    # @method_decorator(csrf_exempt) # 不进行csrf校验
    @method_decorator(csrf_protect) # 进行csrf校验
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)
    
    def get(self, request):
        return HttpResponse('hahaha')

    def post(self, request):
        return HttpResponse('post')

总结:

  1. 在给CBV装饰的时候有区别

    • 需要导入一个固定的装饰器 method_decorator(装饰器,方法名)

    • csrf_exempt这个装饰器比较特殊 装饰的时候 只能给dispatch方法装

  2. 其他的装饰器 自定义的 模块的

    • 直接类外面指名道姓的装
    • 给dispatch装
    • 直接装在方法上
posted @ 2019-10-31 21:39  RandySun  阅读(274)  评论(0编辑  收藏  举报