Django框架之csrf跨站请求

【一】csrf跨站请求伪造详解

  • CSRF(Cross-Site Request Forgery)跨站请求伪造是一种常见的网络攻击方式。
  • 攻击者通过诱导受害者访问恶意网站或点击恶意链接
    • 将恶意请求发送到目标网站上
    • 利用受害者在目标网站中已登录的身份来执行某些操作
    • 从而达到攻击的目的。
  • 要保护自己免受CSRF攻击,网站开发者可以采取以下措施:
    • 使用CSRF令牌:
      • 在用户的请求中添加随机生成的令牌,并将该令牌保存在用户会话中。
      • 每次提交请求时都会验证该令牌,以确保请求是合法的。
  • 启用SameSite属性:
    • 将Cookie的SameSite属性设置为Strict或Lax,以限制跨站请求。
    • 这可以在一定程度上缓解CSRF攻击。
  • 严格验证请求来源:
    • 服务器端可以验证请求的来源是否为预期的网站域名
    • 例如检查HTTP Referer头部。
  • 使用验证码:
    • 在敏感操作(如转账、更改密码等)上使用验证码
    • 增加用户身份验证的防护。

【二】csrf跨域请求伪造

  • 钓鱼网站
    • 搭建一个类似正规网站的页面
    • 用户点击网站链接,给某个用户打钱
    • 打钱的操作确确实实提交给了中国银行的系统,用户的钱也确实减少
    • 但是唯一不同的是,账户打钱的账户不是用户想要打钱的目标账户,变成了其他用户
  • 内部本质
    • 在钓鱼网站的页面针对对方账户,只给用户提供一个没有name属性的普通input框
    • 然后在内部隐藏一个已经写好带有name属性的input框
  • 如何避免上面的问题
    • csrf跨域请求伪造校验
      • 网站在给用户返回一个具有提交数据功能的页面的时候会给这个页面加一个唯一标识
      • 当这个页面后端发送post请求的时候,我们后端会先校验唯一标识
        • 如果成功则正常执行
        • 如果唯一标识不符合则拒绝连接(403 forbidden)

【1】正常服务端

  • 前端
html 复制代码
<h1>这是正规的网站</h1>

<form action="" method="post">
    <p>当前账户 :>>>> <input type="text" name="start_user"></p>
    <p>目标账户 :>>>> <input type="text" name="end_user"></p>
    <p>转账金额 :>>>> <input type="text" name="money"></p>
    <input type="submit">
</form>
  • 后端
python 复制代码
def transform_normal(request):
    if request.method == "POST":
        user_start = request.POST.get("start_user")
        user_end = request.POST.get("end_user")
        money = request.POST.get("money")
        return HttpResponse(f"当前账户 :>>> {user_start} 向目标用户 :>>> {user_end} 转账了 :>>> {money}")
    return render(request, 'transform_normal.html')

【2】钓鱼服务端

html 复制代码
<h1>这是钓鱼的网站</h1>

<form action="http://127.0.0.1:8000/transform_normal/" method="post">
    <p>当前账户 :>>>> <input type="text" name="start_user" ></p>
    <p>目标账户 :>>>> <input type="text"></p>
    <p><input type="text" name="end_user" value="Hopes" style="display: none"></p>
    <p>转账金额 :>>>> <input type="text" name="money"></p>
    <input type="submit">
</form>
python 复制代码
def transform_normal(request):
    if request.method == "POST":
        user_start = request.POST.get("start_user")
        user_end = request.POST.get("end_user")
        money = request.POST.get("money")
        return HttpResponse(f"当前账户 :>>> {user_start} 向目标用户 :>>> {user_end} 转账了 :>>> {money}")
    return render(request, 'transform_normal.html')

【三】csrf校验

【介绍】

  • csrf校验是一种用于防止跨站请求伪造(Cross-Site Request Forgery)攻击的安全措施。

form表单中进行csrf校验:

添加CSRF Token字段:

  • 在form表单中添加一个隐藏字段,用于存储CSRF Token的值。
  • 后端服务器在渲染表单时生成一个CSRF Token,并将其存储在会话中或者以其他方式关联到当前用户。
  • 当用户提交表单时,前端将CSRF Token的值包含在请求中。
  • 后端在验证表单数据时,检查请求中的CSRF Token是否与存储的Token匹配,如果不匹配,则拒绝请求。

设置Cookie:

  • 后端服务器在渲染表单时,在客户端设置一个包含随机生成的CSRF Token的Cookie。
  • 当用户提交表单时,表单数据会被一同发送到服务器,并自动包含该Cookie。
  • 后端在验证表单数据时,检查请求中的CSRF Token是否与Cookie中的值匹配,如果不匹配,则拒绝请求。

双重Cookie校验:

  • 后端服务器在渲染表单时,在Cookie中设置一个随机生成的CSRF Token,并将其存储在会话中或以其他方式关联到当前用户。
  • 当用户提交表单时,表单数据会被一同发送到服务器,请求头或请求参数中携带一个包含CSRF Token的自定义字段。
  • 后端在验证表单数据时,同时检查请求中的CSRF Token和Cookie中的值是否匹配,如果不匹配,则拒绝请求。

【1】form表单如何校验

  • 在form表单上面加上csrf_token
python 复制代码
<form action="" method="post">
{% csrf_token %}
    <p>username:<input type="text" name="username"></p>
    <p>transfer_user<input type="password" name="password"></p>
    <p>money<input type="text" name="money"></p>
    <input type="submit">
</form>
  • 在页面标签中会自动出现一个标签
python 复制代码
<input type="hidden" name="csrfmiddlewaretoken" value="zQaNPZsy1tVmLdqC7GIDOOOfR7yT9YfO58lJ5yrjZfTw2edZTrVYUllOVMnkwXKe">

【2】ajax如何校验

  • 方式一
    • 利用标签查找获取页面上的随机字符串
    • 键必须叫 csrfmiddlewaretoken
html 复制代码
<button id="b1">ajax请求提交</button>

<script>
    $("#b1").click(function () {
        $.ajax({
            url: '',
            type: 'post',
            // (1) 利用标签查找获取页面上的随机字符串
            data: {"username": "dream",
                   "csrfmiddlewaretoken":$('[csrfmiddlewaretoken]').val()},
            success: function () {

            }
        })
    })
</script>
  • 方式二
    • 利用模板语法进行快捷引入
html 复制代码
<button id="b1">ajax请求提交</button>

<script>
    $("#b1").click(function () {
        $.ajax({
            url: '',
            type: 'post',
            // (2) 利用模板语法提供的快捷书写
            data: {"username": "dream", 
                   "csrfmiddlewaretoken": "{{ csrf_token }}"},
            success: function () {

            }
        })
    })
</script>
  • 方式三
    • 定义一个js文件并引入
    • 导入该配置文件之前,需要先导入jQuery,因为这个配置文件内的内容是基于jQuery来实现的
python 复制代码
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);
    }
  }
});

Cross Site Request Forgery protection | Django documentation | Django (djangoproject.com)

html 复制代码
<button id="b1">ajax请求提交</button>

<script>
    $("#b1").click(function () {
        $.ajax({
            url: '',
            type: 'post',
            // (3) 定义外部js文件并引入到本地
            data: {"username": "dream"},
            success: function () {

            }
        })
    })
</script>

【四】csrf相关装饰器

  • 【1】网站整体部分校验csrf,部分不校验csrf
  • 【2】网站整体全部校验csrf,部分不校验csrf

【1】csrf_protect装饰器:

  • csrf_protect装饰器用于需要进行CSRF保护的视图函数或类视图。
  • 当一个视图被csrf_protect装饰器修饰时,Django会对该视图接收到的所有POST、PUT、DELETE等非安全HTTP方法的请求进行CSRF校验。
  • 如果请求中没有有效的CSRF令牌或令牌校验失败,Django将返回403 Forbidden响应。

【2】csrf_exempt装饰器:

  • csrf_exempt装饰器用于不需要进行CSRF保护的视图函数或类视图。
  • 当一个视图被csrf_exempt装饰器修饰时,Django将不会对该视图接收到的任何请求进行CSRF校验。
  • 这个装饰器主要用于一些特殊情况,比如与第三方系统进行集成、开放API接口等。

【3】FBV中使用上述装饰器

python 复制代码
from django.views.decorators.csrf import csrf_protect, csrf_exempt
'''
csrf_protect  需要校验
csrf_exempt   忽视校验
'''
  • 当我们没有注释掉csrf校验中间件的时候,可以在函数头上加上 @csrf_exempt 忽视校验
  • 当我们注释掉csrf校验中间件的时候,可以在函数头上加上 @csrf_protect 强制启动校验

【4】CBV中使用上述装饰器

python 复制代码
from django.views.decorators.csrf import csrf_protect, csrf_exempt
'''
csrf_protect  需要校验
	针对 csrf_protect 符合之前的装饰器的三种用法
csrf_exempt   忽视校验
	针对 csrf_exempt 只能给 dispatch 方法加才有效
'''

(1)csrf_protect

  • (1)方式一
    • 给指定方法加@method_decorator
python 复制代码
from django.views import View
from django.views.decorators.csrf import csrf_protect, csrf_exempt
from django.utils.decorators import method_decorator


class MyCsrf(View):
    def get(self, request):
        return HttpResponse("get")
    
    @method_decorator(csrf_protect)
    def post(self, request):
        return HttpResponse("post")
  • (2)方式二
    • 给类加然后指明方法 @method_decorator
python 复制代码
from django.views import View
from django.views.decorators.csrf import csrf_protect, csrf_exempt
from django.utils.decorators import method_decorator


@method_decorator(csrf_protect)
class MyCsrf(View):
    def get(self, request):
        return HttpResponse("get")
    
    def post(self, request):
        return HttpResponse("post")
  • (3)方式三
    • 重写 dispatch 方法
python 复制代码
from django.views import View
from django.views.decorators.csrf import csrf_protect, csrf_exempt
from django.utils.decorators import method_decorator


class MyCsrf(View):
    @method_decorator(csrf_protect)
    def dispatch(self, request, *args, **kwargs):
        return super(MyCsrf, self).dispatch(request, *args, **kwargs)

    def get(self, request):
        return HttpResponse("get")

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

(2)csrf_exempt方法

  • 只有重写 dispatch方法 有效
python 复制代码
from django.views import View
from django.views.decorators.csrf import csrf_protect, csrf_exempt
from django.utils.decorators import method_decorator


class MyCsrf(View):
    @method_decorator(csrf_exempt)
    def dispatch(self, request, *args, **kwargs):
        return super(MyCsrf, self).dispatch(request, *args, **kwargs)

    def get(self, request):
        return HttpResponse("get")

    
    def post(self, request):
        return HttpResponse("post")
相关推荐
FreakStudio2 小时前
全网最适合入门的面向对象编程教程:56 Python字符串与序列化-正则表达式和re模块应用
python·单片机·嵌入式·面向对象·电子diy
丶21362 小时前
【CUDA】【PyTorch】安装 PyTorch 与 CUDA 11.7 的详细步骤
人工智能·pytorch·python
_.Switch3 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
一个闪现必杀技3 小时前
Python入门--函数
开发语言·python·青少年编程·pycharm
小鹿( ﹡ˆoˆ﹡ )3 小时前
探索IP协议的神秘面纱:Python中的网络通信
python·tcp/ip·php
卷心菜小温4 小时前
【BUG】P-tuningv2微调ChatGLM2-6B时所踩的坑
python·深度学习·语言模型·nlp·bug
陈苏同学4 小时前
4. 将pycharm本地项目同步到(Linux)服务器上——深度学习·科研实践·从0到1
linux·服务器·ide·人工智能·python·深度学习·pycharm
唐家小妹4 小时前
介绍一款开源的 Modern GUI PySide6 / PyQt6的使用
python·pyqt
羊小猪~~5 小时前
深度学习项目----用LSTM模型预测股价(包含LSTM网络简介,代码数据均可下载)
pytorch·python·rnn·深度学习·机器学习·数据分析·lstm
Marst Code5 小时前
(Django)初步使用
后端·python·django