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")
相关推荐
Icomi_34 分钟前
【神经网络】0.深度学习基础:解锁深度学习,重塑未来的智能新引擎
c语言·c++·人工智能·python·深度学习·神经网络
蠟筆小新工程師36 分钟前
Deepseek可以通过多种方式帮助CAD加速工作
开发语言·python·seepdeek
NoBarLing38 分钟前
python将目录下的所欲md文件转化为html和pdf
python·pdf·html
项目題供诗1 小时前
ES语法学习
学习·elasticsearch·django
岱宗夫up1 小时前
【Python】Django 中的算法应用与实现
数据库·python·opencv·django·sqlite
天道有情战天下2 小时前
python flask
开发语言·python·flask
秀儿还能再秀3 小时前
淘宝母婴购物数据可视化分析(基于脱敏公开数据集)
python·数据分析·学习笔记·数据可视化
计算机老学长4 小时前
基于Python的商品销量的数据分析及推荐系统
开发语言·python·数据分析
千益4 小时前
玩转python:系统设计模式在Python项目中的应用
python·设计模式
&白帝&4 小时前
Java @PathVariable获取路径参数
java·开发语言·python