Django 配置CSRF(跨站点请求伪造)保护

Django 配置CSRF(跨站点请求伪造)保护

配置

在项目的setings.py文件中 添加如下。

MIDDLEWARE = [
  
    'django.middleware.csrf.CsrfViewMiddleware',

]

跨域请求伪造保护实现主要分为两步

第一步:

Django 的 CSRF 保护要求请求的Referer 标头与标头中存在的来源相匹配Host。例如,这可以防止针对 的POST请求subdomain.example.com成功api.example.com。如果您需要通过 HTTPS 的跨源不安全请求,继续示例,添加"subdomain.example.com"到此列表。该设置还支持子域,因此您可以添加".example.com"

CSRF_TRUSTED_ORIGINS  =  [ 
    'change.allowed.com' , 
]

Referer 即是打开当下链接的页面的域名

跨域攻击只能直接跳转或者 < form>提交,正常情况是不能伪造Referer的 服务端只要获取到Referer 校验是否合法链接即可,当然这是不能百分百保证的,Referer 的值是由浏览器提供的,虽然 HTTP 协议上有明确的要求,但是每个浏览器对于 Referer 的具体实现可能有差别,并不能保证浏览器自身没有安全漏洞。所以需要第二步来同时保证。

第二步:

通过csrf_token的方式解决,Django会产生在前端HTML页面产生一段随机的字符串即csrf_token,然后通过from表单的形式提交发送到后台,csrf中间件会验证随机字符串是否存放在了form表单当中,根据接收到的随机字符串验证这是否为一个安全的提交。

<form action="/login/" method="post">
        {% csrf_token %}
        <input type="text" name="user" />
        <input type="text" name="pwd" />
        <input type="submit" value="提交" />
    </form>

如图所示 提交时将会发送csrfmiddlewaretoken 给后台

image-20210615153043265

如果是异步请求,我们访问后台接口的时候应在头部信息中传入 csrf_token ,如下所示,先从cookie中获取csrftoken,然后设置请求头,调用接口

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="/login/" method="post">
    <input type="text" name="user" />
    <input type="text" name="pwd" />
    <input type="submit" value="提交" />
    <input id="btn" type="button" value="按钮">
</form>

<script src="http://libs.baidu.com/jquery/2.0.0/jquery.js"></script>
<script src="https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/jquery-cookie/1.4.1/jquery.cookie.js"></script>
<script>
    var csrftoken = $.cookie('csrftoken');
    console.log(csrftoken)
    $(function () {
        $('#btn').click(function () {
            console.log(csrftoken)
            $.ajax({
                url:'/login/',
                type:"POST",
                data:{'username':'root','pwd':'123123'},
                headers:{'X-CSRFToken':csrftoken},
                success:function (arg) {

                }
            })
        })
    })
</script>
</body>
</html>

Django 只要开启CSRF(跨站点请求伪造)保护,每次请求都会在返回的cookie中带有csrftoken

如图所示
在这里插入图片描述

前后端分离项目时

例如一个登录页面,前端技术栈vue+elementUi,后端采用Django

要实现CSRF(跨站点请求伪造)保护 大致分为3步

第一步 获取页面的cookies中csrf的值

这里写了一个util.js 文件,他的作用是根据传入的key 获取cookies中的value,代码如下

export const getCookie = name => {
  var strcookie = document.cookie// 获取cookie字符串
  var arrcookie = strcookie.split('; ')// 分割
  // 遍历匹配
  for (var i = 0; i < arrcookie.length; i++) {
    var arr = arrcookie[i].split('=')
    if (arr[0] === name) {
      return arr[1]
    }
  }
  return ''
}

第二步 编写一个api.js负责发送异步请求 并将csrftoken 加入post请求的请求头

import axios from 'axios'
import Qs from 'qs'
import {getCookie} from '../util/util'
axios.defaults.baseURL = 'http://127.0.0.1:8000'

export const login = params => {
  // 这里获取了Django通过cookies返回给前端的csrftoken的值
  let csrftoken = getCookie('csrftoken')
  let data = Qs.stringify(params)
  return axios.post('/testPlatform/signin/', data, {
    headers: {'Content-Type': 'application/x-www-form-urlencoded', 'X-CSRFToken': csrftoken}
  })
}

如图所示 一进入登录页面 就获取到了cookies
在这里插入图片描述

第三步 实现登录页面点击提交发送登录请求

<template>
  <div class="loginIndex" style="overflow-y:hidden">
  <el-form
    class="login-container"
    ref="AccountForm"
    :model="account"
    :rules="loginRules"
    label-position="left">
    <h3>Login</h3>
    <el-form-item prop="username">
      <el-input
        v-model="account.username"
        type="text"
        placeholder="账号">
      </el-input>
    </el-form-item>
    <el-form-item prop="password">
      <el-input v-model="account.password" type="password" placeholder="密码"></el-input>
    </el-form-item>

    <el-form-item>
      <el-button @click.native.prevent="handleLogin" :loading="logining" type="primary">login</el-button>
      <el-button
        type="primary"
        class="resetBtn"
        @click.native.prevent="reset">
        reset
      </el-button>
    </el-form-item>

  </el-form>
  </div>
</template>

<script>
import {login} from '../axios/api'

export default {
  name: 'login',
  data () {
    return {
      account: {
        username: '',
        password: ''
      },
      loginRules: {
        username: [{required: true, message: '请输入账号', trigger: 'blur'}],
        password: [{required: true, message: '请输入密码', trigger: 'blur'}]
      },
      logining: false
    }
  },
  methods: {
    handleLogin () {
      this.$refs.AccountForm.validate((valid) => {
        if (valid) {
          this.logining = true
          let loginParams = {
            username: this.account.username,
            password: this.account.password
          }
          // 调用axios登录接口
          login(loginParams).then(res => {
            // debugger;
            this.logining = false
            // 根据返回的ret判断是否成功
            let { ret, user, msg, expiry } = res.data
            if (ret === 0) {
              // elementui中提示组件
              this.$message({
                type: 'success',
                message: '登陆成功'
              })
              // 登陆成功,用户信息就保存在localStorage中
              localStorage.setItem('user', user)
              localStorage.setItem('expiry', expiry)
              // 跳转到后台主页面
              this.$router.push({ path: '/home' })
            } else {
              this.$message({
                type: 'error',
                message: msg
              })
            }
          }).catch(err => {
            console.log(err)
          })
        } else {
          console.log('error submit!')
          return false
        }
      })
    },
    reset () {
      this.$refs.AccountForm.resetFields()
    }
  }
}
</script>

<style scoped>
  body{
    background: #DFE9FB;
  }
  .login-container {
    width:350px;
    margin-left:40%;
    border: 1px solid #d3d3d3;
    box-sizing: border-box;
    padding: 10px 30px;
    border-radius: 5px;
    margin-top: 100px;
  }
  .el-button {
    width:100%;
    box-sizing: border-box;
    margin: 10px 0;
  }

</style>

此时,点击登录就会携带csrf登录成功了
在这里插入图片描述

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值