Flask框架 CSRF 保护实现方法详解


Posted in Python onOctober 30, 2019

本文实例讲述了Flask框架 CSRF 保护实现方法。分享给大家供大家参考,具体如下:

Flask CSRF 保护

为什么需要 CSRF?

Flask-WTF 表单保护你免受 CSRF 威胁,你不需要有任何担心。尽管如此,如果你有不包含表单的视图,那么它们仍需要保护。

例如,由 AJAX 发送的 POST 请求,然而它背后并没有表单。在 Flask-WTF 0.9.0 以前的版本你无法获得 CSRF 令牌。这是为什么我们要实现 CSRF。

具体操作步骤

根据 csrf_token 校验原理,具体操作步骤有以下几步:
1.后端生成 csrf_token 的值,在前端请求登录或者注册界面的时候将值传给前端,传给前端的方式可能有以下两种:
在模板中的 From 表单中添加隐藏字段
将 csrf_token 使用 cookie 的方式传给前端
2.在前端发起请求时,在表单或者在请求头中带上指定的 csrf_token
3.后端在接受到请求之后,取到前端发送过来的 csrf_token,与第1步生成的 csrf_token 的值进行校验
4.如果校验对 csrf_token 一致,则代表是正常的请求,否则可能是伪造请求,不予通过

而在 Flask 中,CSRFProtect 这个类专门只对指定 app 进行 csrf_token 校验操作,所以开发者需要做以下几件事情:
生成 csrf_token 的值
将 csrf_token 的值传给前端浏览器
在前端请求时带上 csrf_token 值

实现

后端书写

为了能够让所有的视图函数受到 CSRF 保护,你需要开启 CsrfProtect 模块:

from flask_wtf.csrf import CsrfProtect
CsrfProtect(app)

像任何其它的 Flask 扩展一样,你可以惰性加载它:

from flask_wtf.csrf import CsrfProtect
csrf = CsrfProtect()

def create_app():
  app = Flask(__name__)
  csrf.init_app(app)

Note
你需要为 CSRF 保护设置一个秘钥。通常下,同 Flask 应用的 SECRET_KEY 是一样的。

在表单添加保护

如果模板中存在表单,你不需要做任何事情。与之前一样:

<form method="post" action="/">
  {{ form.csrf_token }}
</form>

但是如果模板中没有表单,你需要一个 CSRF 令牌:

<form method="post" action="/">
  <input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
</form>

自定义错误响应和关闭保护

无论何时未通过 CSRF 验证,都会返回 400 响应。你可以自定义这个错误响应:

@csrf.error_handler
def csrf_error(reason):
  return render_template('csrf_error.html', reason=reason), 400

我们强烈建议你对所有视图启用 CSRF 保护。但也提供了某些视图函数不需要保护的装饰器:

@csrf.exempt
@app.route('/foo', methods=('GET', 'POST'))
def my_handler():
  # ...
  return 'ok'

默认情况下你也可以在所有的视图中禁用 CSRF 保护,通过设置 WTF_CSRF_CHECK_DEFAULT 为 False,仅仅当你需要的时候选择调用 csrf.protect()。这也能够让你在检查 CSRF 令牌前做一些预先处理:

@app.before_request
def check_csrf():
  if not is_oauth(request):
    csrf.protect()

ajax提交数据

不需要表单,通过 AJAX 发送 POST 请求成为可能。Flask0.9.0 版本后这个功能变成可用的。

  • 假设你已经使用了 CsrfProtect(app),你可以通过 {{ csrf_token() }} 获取 CSRF
    令牌。这个方法在每个模板中都可以使用,你并不需要担心在没有表单时如何渲染 CSRF 令牌字段。

我们推荐的方式是在 meta 标签中渲染 CSRF 令牌:

<meta name="csrf-token" content="{{ csrf_token() }}">

在 script 标签中渲染同样可行:

<script type="text/javascript">
  var csrftoken = "{{ csrf_token() }}"
</script>

下面的例子采用了在 meta标签渲染的方式, 在 script 中渲染会更简单,你无须担心没有相应的例子。

无论何时你发送 AJAX POST 请求,为其添加 X-CSRFToken 头:

var csrftoken = $(‘meta[name=csrf-token]').attr(‘content')

KaTeX parse error: Expected '}', got 'EOF' at end of input: …|OPTIONS|TRACE)/i.test(settings.type) && !this.crossDomain) {
xhr.setRequestHeader(“X-CSRFToken”, csrftoken)
}
}
})

或者这么写ajax:
在提交请求时,需要在请求头中添加 X-CSRFToken 的键值对

$.ajax({
  ...
  headers: {
    "X-CSRFToken": getCookie("csrf_token")
  },
  ...
})

故障排除

当你定义你的表单的时候,如果犯了这个错误 : 从 wtforms 中导入 Form 而不是从 flask.ext.wtf 中导入,CSRF 保护的大部分功能都能工作(除了 form.validate_on_submit()),但是 CSRF 保护将会发生异常。在提交表单的时候,你将会得到 Bad Request/CSRF token missing or incorrect 错误。这个错误的出现就是因为你的导入错误,而不是你的配置问题。

希望本文所述对大家基于flask框架的Python程序设计有所帮助。

Python 相关文章推荐
用python实现的去除win下文本文件头部BOM的代码
Feb 10 Python
解析Python中的变量、引用、拷贝和作用域的问题
Apr 07 Python
状态机的概念和在Python下使用状态机的教程
Apr 11 Python
Python中的测试模块unittest和doctest的使用教程
Apr 14 Python
python基于property()函数定义属性
Jan 22 Python
python自动脚本的pyautogui入门学习
Apr 01 Python
python 穷举指定长度的密码例子
Apr 02 Python
使用python批量转换文件编码为UTF-8的实现
Apr 03 Python
使用keras内置的模型进行图片预测实例
Jun 17 Python
python字符串的index和find的区别详解
Jun 20 Python
使用Python实现NBA球员数据查询小程序功能
Nov 09 Python
matplotlib运行时配置(Runtime Configuration,rc)参数rcParams解析
Jan 05 Python
使用Python和OpenCV检测图像中的物体并将物体裁剪下来
Oct 30 #Python
python基于K-means聚类算法的图像分割
Oct 30 #Python
Python列表原理与用法详解【创建、元素增加、删除、访问、计数、切片、遍历等】
Oct 30 #Python
Python文件路径名的操作方法
Oct 30 #Python
Python元组 tuple的概念与基本操作详解【定义、创建、访问、计数、推导式等】
Oct 30 #Python
解决python 上传图片限制格式问题
Oct 30 #Python
Python字典的概念及常见应用实例详解
Oct 30 #Python
You might like
PHP 金额数字转换成英文
2010/05/06 PHP
php各种编码集详解和以及在什么情况下进行使用
2011/09/11 PHP
php 保留字列表
2012/10/04 PHP
php跨站攻击实例分析
2014/10/28 PHP
PHP记录页面停留时间的方法
2016/03/30 PHP
微信利用PHP创建自定义菜单的方法
2016/08/01 PHP
javascript简易缓动插件(源码打包)
2012/02/16 Javascript
SwfUpload在IE10上不出现上传按钮的解决方法
2013/06/25 Javascript
jquery自动切换tabs选项卡的具体实现
2013/12/24 Javascript
JS中Date日期函数中的参数使用介绍
2014/01/02 Javascript
js+css简单实现网页换肤效果
2015/12/29 Javascript
JS获取时间的相关函数及时间戳与时间日期之间的转换
2016/02/04 Javascript
jQuery替换节点用法示例(使用replaceWith方法)
2016/09/08 Javascript
jquery控制页面的展开和隐藏实现方法(推荐)
2016/10/15 Javascript
关于Vue.js 2.0的Vuex 2.0 你需要更新的知识库
2016/11/30 Javascript
Jquery给当前页或者跳转后页面的导航栏添加选中后样式的实例
2016/12/08 Javascript
bootstrap网格系统使用方法解析
2017/01/13 Javascript
JS添加或删除HTML dom元素的方法实例分析
2019/03/05 Javascript
nodejs中使用archive压缩文件的实现代码
2019/11/26 NodeJs
详解vue 组件的实现原理
2020/11/12 Javascript
[01:09]DOTA2次级职业联赛 - 99战队宣传片
2014/12/01 DOTA
深度剖析使用python抓取网页正文的源码
2014/06/11 Python
Python最基本的输入输出详解
2015/04/25 Python
Python简单实现控制电脑的方法
2018/01/22 Python
Python实现的微信好友数据分析功能示例
2018/06/21 Python
搞清楚 Python traceback的具体使用方法
2019/05/13 Python
对PyQt5基本窗口控件 QMainWindow的使用详解
2019/06/19 Python
Tensorflow矩阵运算实例(矩阵相乘,点乘,行/列累加)
2020/02/05 Python
TensorFlow固化模型的实现操作
2020/05/26 Python
python实现暗通道去雾算法的示例
2020/09/27 Python
CSS3混合模式mix-blend-mode/background-blend-mode简介
2018/03/15 HTML / CSS
关于box-sizing的全面理解
2016/07/28 HTML / CSS
HTML5 canvas画矩形时出现边框样式不一致的解决方法
2013/10/14 HTML / CSS
你所知道的集合类都有哪些?主要方法?
2012/12/31 面试题
求职信的七个关键技巧
2014/02/05 职场文书
机关单位工作失职检讨书
2014/11/20 职场文书