Django configures CSRF (Cross Site Request Forgery) protection

Posted by davidlenehan on Sat, 29 Jan 2022 16:04:09 +0100

Django configures CSRF (Cross Site Request Forgery) protection

to configure

In the project settings Add the following to the PY file.

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

]

The implementation of cross domain Request Forgery protection is mainly divided into two steps

Step 1:

Django's CSRF protection requires the Referer header of the request to match the source present in the header. This prevents, for example, a subdomain. From being requested for a POST example.com success API example.com. If you need cross source insecure requests over HTTPS, continue with the example and add "subdomain.example.com" to this list. This setting also supports subdomains, so you can add ". example.com"

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

Referer is the domain name of the page that opens the current link

Cross domain attacks can only jump directly or submit < form >. Normally, the server of Referer cannot be forged. Just get the Referer to verify whether the link is legal. Of course, this cannot be guaranteed. The value of Referer is provided by the browser. Although there are clear requirements on the HTTP protocol, the specific implementation of Referer may be different for each browser, There is no guarantee that the browser itself has no security vulnerabilities. So the second step is needed to ensure at the same time.

Step 2:

Through csrf_ To solve the problem by token, Django will generate a random string in the front-end HTML page, namely csrf_ The token is then submitted and sent to the background in the form of from form. The csrf middleware will verify whether the random string is stored in the form form, and verify whether it is a safe submission according to the received random string.

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

As shown in the figure, csrfmiddlewaretoken will be sent to the background when submitting

If it is an asynchronous request, we should pass CSRF in the header information when accessing the background interface_ Token, as shown below, first obtain the csrftoken from the cookie, then set the request header and call the interface

<!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="Submit" />
    <input id="btn" type="button" value="Button">
</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 only needs to turn on CSRF (Cross Site Request Forgery) protection, and each request will contain csrftoken in the returned cookie

As shown in the figure

When separating items at the front and rear ends

For example, for a login page, the front-end technology stack vue+elementUi and the back-end Django are used

To realize CSRF (Cross Site Request Forgery) protection, it is roughly divided into three steps

The first step is to obtain the value of csrf in the cookies of the page

Here is a util JS file. Its function is to obtain the value in the cookies according to the passed in key. The code is as follows

export const getCookie = name => {
  var strcookie = document.cookie// Get cookie string
  var arrcookie = strcookie.split('; ')// division
  // Ergodic matching
  for (var i = 0; i < arrcookie.length; i++) {
    var arr = arrcookie[i].split('=')
    if (arr[0] === name) {
      return arr[1]
    }
  }
  return ''
}

The second step is to write an API JS is responsible for sending asynchronous requests and adding csrftoken to the request header of post requests

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 => {
  // Here we get the value of the csrftoken returned by Django to the front end through cookies
  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}
  })
}

As shown in the figure, cookies are obtained as soon as you enter the login page

Step 3: click submit on the login page to send the login request

<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="account number">
      </el-input>
    </el-form-item>
    <el-form-item prop="password">
      <el-input v-model="account.password" type="password" placeholder="password"></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: 'Please enter the account number', trigger: 'blur'}],
        password: [{required: true, message: 'Please input a password', 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
          }
          // Call axios login interface
          login(loginParams).then(res => {
            // debugger;
            this.logining = false
            // Judge whether it is successful according to the ret returned
            let { ret, user, msg, expiry } = res.data
            if (ret === 0) {
              // Prompt component in elementui
              this.$message({
                type: 'success',
                message: 'Login successful'
              })
              // After successful login, the user information is saved in localStorage
              localStorage.setItem('user', user)
              localStorage.setItem('expiry', expiry)
              // Jump to the background main page
              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>

At this point, click login and the csrf login will be successful

Topics: Django