4.1 Web 表单

4.1.1 跨站请求伪造保护

跨站请求伪造(CSRF):是一种挟制用户在当前已登录的 Web 应用程序上执行非本意的操作的攻击方法。

CSRF 攻击原理:

  • 用户打开浏览器,访问受信任网站 A。登录成功后,网站 A 产生 Cookie 信息并返回给浏览器。

  • 用户未退出网站 A 之前,在同一浏览器中,打开一个页面访问网站 B。

  • 网站 B 接收到用户请求后,返回一些攻击性代码,并发出一个请求要求访问第三方站点A。

  • 浏览器在接收到这些攻击性代码后,根据网站B的请求,在用户不知情的情况下携带 Cookie 信息,向网站A发出请求。网站 A 并不知道该请求其实是由 B 发起的,所以会根据用户的 Cookie 信息处理该请求,导致来自网站 B 的恶意代码被执行。

image1

在 Flask 中, Flask-WTF 可以保护表单免受跨站请求伪造攻击。为了实现 CSRF 保护,Flask-WTF 需要应用程序配置一个加密密钥。Flask-WTF 使用这个加密密钥去生成安全令牌存储在用户会话中,用于验证请求表单数据的真实性。

示例:在 Flask 应用中配置密钥

app = Flask(__name__)
app.config['SECRET_KEY'] = 'hard to guess string'

app.config 字典可用来存储 Flask、扩展和程序自身的配置变量。

4.1.2 表单类

使用 Flask-WTF 时, 在服务器端,每个 Web 表单都是由一个继承 FlaskForm 的类表示。这个类定义表单中的一组字段,每个字段都用对象表示。字段对象可附属一个或多个验证函数,用于验证用户提交的数据是否有效。

示例:定义一个简单的 Web 表单,包含一个文本字段和一个提交按钮。

from flask_wtf import FlaskForm
from wtforms import StringField,SubmitField
from wtforms.validators import DataRequired

class NameForm(FlaskForm):
    name = StringField('What is your name?',validators=[DataRequired()])
    submit = SubmitField('Submit')

WTForms支持的 HTML 标准字段(部分):

字段类型

说明

BooleanField

复选框,值为 True 和 False

FileField

文件上传字段

TextAreaField

多行文本字段

StringField

文本字段

SubmitField

表单提交按钮

SelectField

下拉列表

PsswordField

密码文本字段

HiddenField

隐藏的文本字段

WTForms 内建的验证函数(部分):

验证函数

说明

DataRequired

确保转换类型后的字段中有数据

Email

验证电子邮件地址

EqualTo

比较两个字段的值;常用于要求输入两次密码进行确认的情况

InputRequired

确保转换类型前字段中有数据

IPAddress

验证 IPV4 网络地址

Length

验证输入字符串的长度

Regexp

使用正则表达式验证输入值

4.1.3 把表单渲染成HTML

表单字段是可调用的,在模板中调用后会渲染成 HTML。假设视图函数通过 form 参数把一个 NameForm 实例传入模板,在模板中生成一个简单的HTML 表单:

<form method="POST">
    {{ form.name.label }} {{ form.name() }}
    {{ form.submit() }}
</form>

除了上面这种简单的方式,还可以使用 Flask-Bootstrap 渲染表单:

{% import "boostrap/wtf.html" as wtf %}
{{ wtf.quick_form(form) }}

4.1.4 在视图函数中处理表单

在视图函数中有两个任务:接收用户在表单中填写的数据、渲染表单。

示例:

@app.route('/',methods=['GET','POST'])
def index():
    name = None
    form = NameForm()
    if form.validate_on_submit():
        name = form.name.data
        form.name.data = ''
    return render_template('index.html', form=form, name=name)