Djiango:csrf跨站请求伪造
一、csrf跨站请求伪造
1.csrf简介
CSRF跨站点请求伪造Cross Site Request Forgery,是一种挟持用户在当前已登录的web应用程序上执意非本意的操作的攻击方法。
攻击者盗用了你的身份,以你的名义发送恶意请求,对服务器来说这个请求是完全合法的,但是却完成了攻击者所期望的一个操作,比如以你的名义发送邮件、发消息,盗取你的账号,添加系统管理员,甚至于购买商品、虚拟货币转账等。
2.模拟钓鱼网站案例
某个钓鱼网站,从网址到页面都和真银行网站一摸一样,当你想要通过银行操作业务的时候,他会将你的银行卡号和密码发送给真的银行,但是转账人取被改成洗钱的账户(隐藏的input框)提交给银行,然后通过真银行将钱转走。

- 后端
def transfer_func(request):
    if request.method == "POST":
        username = request.POST.get('username')
        transfer_name = request.POST.get('transfer_name')
        money = request.POST.get('money')
        print(f"{username}给{transfer_name}转账了{money}元")
    return render(request, 'transferPage.html')
- 
钓鱼网站前端 通过内部隐藏标签,将用户想要转账的转账人更改 

二、csrf相关校验策略
在settings中解开注释,开启csrf验证机制,当我们提交POST请求时,在提交数据的位置添加唯一标识,以供后续校验使用

1.form的csrf策略
在form表单内部添加模版语法
{% csrf_token %}

在web浏览器的页面上则会多一个input标签出来,属性name="csrfmiddlewaretoken",value为随机字符串

2.ajax请求csrf策略
(1)方式1:自己手动取值,较为繁琐
在data中添加一个键值对为'csrfmiddlewaretoken':$('input[name="csrfmiddlewaretoken"]').val()
        $('.c1').click(function (){
        $.ajax({
            url:'',
            type:'post',
            data:{
                'csrfmiddlewaretoken':$('input[name="csrfmiddlewaretoken"]').val(),
                'username':'duoduo',
                'transfer_name':'qiuqiu',
                'money':11111,
            },
            success:function (args){
            }
        })
    })

(2)方式2:利用模版语法自动获取(一定要用引号引起来)
在data中添加一个'csrfmiddlewaretoken':'{{ csrf_token },自动传一个token
    $('.c1').click(function (){
        $.ajax({
            url:'',
            type:'post',
            data:{
                'csrfmiddlewaretoken':'{{ csrf_token }}',
                'username':'duoduo',
                'transfer_name':'qiuqiu',
                'money':11111,
            },
            success:function (args){
            }
        })
    })

(3)方式3:直接引入一个js脚步(官网提供的)
通过静态文件,为所有ajax发送请求时自动添加上csrftoken及其随机字符串。
在static中新建一个js文件,将脚本拷贝进去,并在网页上连接进去
参考:https://www.cnblogs.com/Dominic-Ji/p/9234099.html
- csrf.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);
    }
  }
});
三、csrf相关视图验证
需求:整个django项目都校验csrf,但是某些视图函数/类不校验csrf。
解决:使用csrf提供的装饰器
1.FBV添加csrf校验装饰器
在视图中,为某个函数单独设置需要csrf校验,或者取消单独某个函数的csrf校验。
需要导入以下两个模块。
from django.views.decorators.csrf import csrf_protect # 单独校验
from django.views.decorators.csrf import csrf_exempt  # 取消校验
- 
@csrf_exempt当添加exempt装饰器时,就算在settings中还保存着csrf校验,该函数对应的路由地址也不会开启csrf校验 
@csrf_exempt
def transfer_func(request):pass
- 
@csrf_protect添加protect装饰器,则会开启csrf校验 
@csrf_protect
def transfer_func(request):pass
2.CBV添加csrf校验装饰器
当我们和FBV一样添加相同的装饰器给类中的函数的时候,并不会直接报错csrf验证,而是没有cookies。

所以,不能直接给在CBV中的方法添加装饰器,需要导入一个模块,通过该模块的装饰器,给CBV中的方法添加csrf校验功能
# 使用CBV的模块,CBV需要继承该类
from django.views import View  
# 添加csrf装饰器的模块
from django.utils.decorators import method_decorator

(1)方式1:单独生效,针对某个方法添加csrf装饰器
class ...():
    @method_decorator(csrf_protect)
    def post():
(2)方式2:单独生效
给类中的某一个方法添加装饰器
@method_decorator(csrf_protect, name='post')
class MyView(View):
    def post(self, request):
        return HttpResponse('这里是 MyView 的post')

(3)方式3:给整个类中生效
重写dispatch方法,dispatch是整个CBV方法分发的入口
class MyView(View):
    @method_decorator(csrf_protect)  # 方式3:重写dispatch方法,为整个类中的方法添加csrf校验
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)
    def post(self, request):
        return HttpResponse('这里是 MyView 的post')

特例:csrf_exempt只有第三种方法生效,其他的不方法不支持
 
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号