六十六:CSRF攻击与防御之CSRF防御之ajax防御和ajax封装

 

app里面还是要绑定CSRFProtect

from flask_wtf import CSRFProtect # flask_wtf 已经提供CSRF的防御手段
CSRFProtect(app) # 绑定app

 

登录页的js

$(function () {
$('#submit').click(function (event) {
event.preventDefault(); // 阻止默认form提交表单行为
var email = $('input[name=email]').val();
var password = $('input[name=password]').val();
var csrf_token = $('input[name=csrf_token]').val();
// ajax
$.post({
'url': '/login/',
'data': {
'email': email,
'password': password,
'csrf_token': csrf_token
},
'success': function (data) {
console.log(data)
},
'fail': function (error) {
console.log(error)
}
});
});
});

在页面里面引入js

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录</title>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
<script src="{{url_for('static', filename='login.js')}}"></script>
</head>
<body>
<form action="" method="post">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<table>
<tbody>
<tr>
<td>邮箱:</td>
<td><input type="text" name="email"></td>
</tr>
<tr>
<td>密码:</td>
<td><input type="text" name="password"></td>
</tr>
<tr>
<td></td>
<td><input id="submit" type="submit" value="点击登录"></td>
</tr>
</tbody>
</table>
</form>
</body>
</html>

请求页面

 

以上方法虽能使用csrf_token防御,可需要在每一个提交页面都写,flask推荐的方式是将csrf_token()放到meta标签下下,发送数据时,放到头部信息中

使用jinja的模板继承功能,base模板:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta name="csrf_token" content="{{ csrf_token() }}">
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
{% block head %}{% endblock %}
</head>
<body>
<nav>导航条</nav>
{% block body %}{% endblock %}
<footer>底部</footer>
</body>
</html>

登录页继承base模板

{% extends 'base.html' %}

{% block head %}
<script src="{{url_for('static', filename='login.js')}}"></script>
{% endblock %}

{% block body %}
<form action="" method="post">
<table>
<tbody>
<tr>
<td>邮箱:</td>
<td><input type="text" name="email"></td>
</tr>
<tr>
<td>密码:</td>
<td><input type="text" name="password"></td>
</tr>
<tr>
<td></td>
<td><input id="submit" type="submit" value="点击登录"></td>
</tr>
</tbody>
</table>
</form>
{% endblock %}

登录页的js,将csrf放到头部信息

$(function () {
$('#submit').click(function (event) {
event.preventDefault(); // 阻止默认form提交表单行为
var email = $('input[name=email]').val();
var password = $('input[name=password]').val();
var csrf_token = $('meta[name=csrf_token]').attr('content');

//设置头部信息
$.ajaxSetup({
'beforeSend': function (xhr, settings) {
if(!/^(GET|HEAD|OPTIPNS|TRACE)$/i.test(settings.type) && !this.crossDomain){
xhr.setRequestHeader('X-CSRFToken', csrf_token)
}
}
});

// ajax
$.post({
'url': '/login/',
'data': {
'email': email,
'password': password,
},
'success': function (data) {
console.log(data)
},
'fail': function (error) {
console.log(error)
}
});
});
});

访问

 

由于每个js请求都需要在头部信息里面添加此参数,所以可以将添加头部信息拿出来封装

封装一个统一的ajax,每次自动获取csrftoken并加到头部信息中

var http = {
'get':function (args) {
args['method'] = 'get';
this.ajax(args);
},
'post':function (args) {
args['method'] = 'post';
this.ajax(args);
},
'ajax':function (args) { // 将头部信息放到请求
this._ajaxSetup();
$.ajax(args);
},
'_ajaxSetup':function(){ // 将csrftoken放到头部信息
$.ajaxSetup({
'beforeSend': function (xhr, settings) {
if(!/^(GET|HEAD|OPTIPNS|TRACE)$/i.test(settings.type) && !this.crossDomain){
var csrf_token = $('meta[name=csrf_token]').attr('content'); // 获取csrf_token
xhr.setRequestHeader('X-CSRFToken', csrf_token)
}
}
});
}
};

登录页的js,使用自定义的ajax机制

$(function () {
$('#submit').click(function (event) {
event.preventDefault(); // 阻止默认form提交表单行为
var email = $('input[name=email]').val();
var password = $('input[name=password]').val();

// 使用自定义的ajax
http.post({
'url': '/login/',
'data': {
'email': email,
'password': password,
},
'success': function (data) {
console.log(data)
},
'fail': function (error) {
console.log(error)
}
});
});
});

base模板中导入ajax的js

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta name="csrf_token" content="{{ csrf_token() }}">
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
<script src="{{ url_for('static', filename='send_http.js') }}"></script>
{% block head %}{% endblock %}
</head>
<body>
<nav>导航条</nav>
{% block body %}{% endblock %}
<footer>底部</footer>
</body>
</html>

请求

 

这样发送请求的时候使用自己封装的ajax就可以实现每次发送请求的时候自动在头部信息加上csrftoken信息

 

posted @ 2019-11-16 18:28  向前走。  阅读(619)  评论(0编辑  收藏  举报