Django基础(12)_csrf跨站请求伪造
什么是CSRF
详述CSRF(Cross-site request forgery),中文名称:跨站请求伪造,也被称为:one click attack/session riding,缩写为:CSRF/XSRF。攻击者通过HTTP请求江数据传送到服务器,从而盗取回话的cookie。盗取回话cookie之后,攻击者不仅可以获取用户的信息,还可以修改该cookie关联的账户信息。

服务器验证token的原理
token字符串的前32位是salt(盐), 后面是加密后的token, 通过salt能解密出唯一的secret。 django会验证表单中的token和cookie中token是否能解出同样的secret,secret一样则本次请求合法。
表单中的csrfmiddletoken, cookie中的csrftoken
1 在响应的页面中加入{% csrf_token %}标签,那么在进行模板渲染是会生成如下标签 <input type="hidden" name="csrfmiddlewaretoken" value="ppwN8yg1wVEyXDxtMpVIrc4zV3gHiDKKb9rwGPLaSGRc0HKhXAwpNrKjGDUHIxjj"> 2 并且在响应还有这个 {% csrf_token %}标签的页面时,会添加cookie键值对,如下 csrftoken:lsMQeJgVbIKKxlfz6umgYM8WOWx1Njr77cHzM0L4xtXoApsnhFXXk1OGzwb1dd0G 3 当用户从该页面提交数据时,会携带csrfmiddlewaretoken:ppwN8yg1wVEyXDxtMpVIrc4zV3gHiDKKb9rwGPLaSGRc0HKhXAwpNrKjGDUHIxjj和cookie键值对 4 取出cookie中的csrftoken值和请求数据部分的csrfmiddlewaretoken的值,两者进行比较,这个随机字符串叫做token字符串. django如果在请求数据部分找不到tokne值,会去请求数据中的请求行部分,找一个叫做X-CSRFToken的键值对,如果这个键对应的值和cookie中csrftoken对应的值相同,也能通过认证. 过程: token字符串的前32位是salt, 后面是加密后的token, 通过salt能解密出唯一的secret字符串。 secret:是settings配置文件中的serect_key: SECRET_KEY = 's!xbzez1zxrevmq7k_89%%-z&#)e7686pyq8pg@_bp_k_2s^ho' django会验证表单中的token和cookie中token是否能解出同样的secret,secret一样则本次请求合法。 如果不同就403 forbidden
form表单中的token
服务器给表单中返回一个csrfmiddlewaretoken

cookie中的token
当用户提交get请求, 服务器就会给浏览器的cookie中返回一个csrftoken

form表单设置token
<!--form表单中验证token--> <h1>天上人间会员登录页面</h1> <form action="" method="post" > {% csrf_token %} <div>{{ error }}</div> 用户名: <input type="text" name="username" value="{{ username }}"> 密码: <input type="password" name="password" value="{{ password }}"> <input type="submit"> </form>
ajax通过django的csrf_token验证
首先我们先看一下不给ajax请求设置csrf_token的情况

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>fivenian</title> </head> <body> <!--form表单中验证token--> {#<h1>天上人间会员登录页面</h1>#} {#<form action="" method="post" >#} {# {% csrf_token %}#} {# <div>{{ error }}</div>#} {# 用户名: <input type="text" name="username" value="{{ username }}">#} {# 密码: <input type="password" name="password" value="{{ password }}">#} {# <input type="submit">#} {#</form>#} <!--ajax验证token--> <h1>ajax的token认证</h1> 用户名: <input type="text" name="username" id="id_username"> <br> 密码: <input type="password" name="password" id="id_password"> <br> <button id="btn">登录</button> <h3 id="error_msg"></h3> <!--若请求失败打印一下错误信息--> <h3 id="success_msg"></h3> </body> <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script> <script> $('#btn').click(function (){ var username = $('#id_username').val(); var password = $('#id_password').val(); $.ajax({ url:'/login/', type:'post', data:{'uname':username,'pwd':password}, success:function (res){ $('#success_msg').text('请求成功') }, error(error){ console.log(error) $('#error_msg').text(error.responseText) } }) }) </script> </html>
ajax请求中添加csrf_token的三种方式
方法一: 在我们的body代码中添加上 {% csrf_token %} , 然后获取token添加在data中发送到服务器
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>fivenian</title> </head> <body> <!--ajax验证token--> <h1>ajax的token认证</h1> {% csrf_token %} <!--在body中添加上--> 用户名: <input type="text" name="username" id="id_username"> <br> 密码: <input type="password" name="password" id="id_password"> <br> <button id="btn">登录</button> <h3 id="error_msg"></h3> <!--若请求失败打印一下错误信息--> <h3 id="success_msg"></h3> </body> <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script> <script> $('#btn').click(function (){ var username = $('#id_username').val(); var password = $('#id_password').val(); var token = $("[name='csrfmiddlewaretoken']").val() // 获取token 然后加到data中 $.ajax({ url:'/login/', type:'post', data:{uname:username,pwd:password,csrfmiddlewaretoken:token}, success:function (res){ $('#success_msg').text('请求成功') }, error(error){ console.log(error) $('#error_msg').text(error.responseText) } }) }) </script> </html>
# views.py
def login(request): if request.method == 'POST': print(request.POST) rep = HttpResponse('not ok') rep.status_code = 400 return rep return render(request, 'home/login.html')
然后在提交一下我们的form表单,可以看到访问成功,我们返回的错误也打印了出来

方法二: 直接在data中将token对应的随机字符串发送过去,
csrfmiddlewaretoken:'{{ csrf_token }}'

提交表单可以看到 变成了随时字符串
$('#btn').click(function (){ var username = $('#id_username').val(); var password = $('#id_password').val(); // var token = $("[name='csrfmiddlewaretoken']").val() $.ajax({ url:'/login/', type:'post', data:{uname:username,pwd:password,csrfmiddlewaretoken:'{{ csrf_token }}'}, // 这里的{{ csrf_token }} 拿到的就是 {% csrf_token %}生成的input标签中的value属性对应的token值 success:function (res){ $('#success_msg').text('请求成功') }, error(error){ console.log(error) $('#error_msg').text(error.responseText) } }) })
方法三: 添加请求头键值对, 键必须叫做 X-CSRFToken , 值就是cookie中的token值
jquery操作cookie,下载jquery.cookie.js文件
# 我们需要使用jquery操作cookie,所以先下载文件 http://plugins.jquery.com/cookie/ https://www.bootcdn.cn/jquery-cookie/
注意:
如果使用从cookie中取csrftoken的方式,需要确保cookie存在csrftoken值。
如果你的视图渲`染的HTML文件中没有包含 {% csrf_token %},Django可能不会设置CSRFtoken的cookie。
这个时候需要使用ensure_csrf_cookie()装饰器强制设置Cookie。
django.views.decorators.csrf import ensure_csrf_cookie @ensure_csrf_cookie def login(request): pass
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script> <script src="https://cdn.bootcdn.net/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.js"></script> <script> $('#btn').click(function (){ var username = $('#id_username').val(); var password = $('#id_password').val(); // var token = $("[name='csrfmiddlewaretoken']").val() $.ajax({ type:'post', url:'/login/', data:{uname:username,pwd:password}, headers:{ // 设置响应头键值对 'X-CSRFToken': $.cookie('csrftoken'), }, success:function (res){ $('#success_msg').text('请求成功') }, error(error){ console.log(error) $('#error_msg').text(error.responseText) } }) }) </script>
既然使用了 jquery.cookie.js 我们就介绍下使用jquery操作cookie
添加cookie
$.cookie('the_cookie', 'the_value');
读取cookie
$.cookie('the_cookie'); #the_cookie是键
删除cookie
$.cookie('the_cookie', null); //通过传递null作为cookie的值即可
------------恢复内容结束------------
本文来自博客园,作者:长情不羁的五年,转载请注明原文链接:https://www.cnblogs.com/grlend/articles/14081579.html

浙公网安备 33010602011771号