Flask实现CSRF保护

  参考官方文档

 CSRF跨站请求伪造,源于WEB的隐式身份验证机制,WEB的身份验证机制虽然可以抱着一个请求时来自于某个用户的浏览器,但却无法保证该请求是用户批准发送的。

 例如,用户登录受信任的网址A,在本地生成了Cookie,在Cookie没有失效的情况下去访问了危险网站B,B可能会盗用你的身份,以你的名义去发送恶意请求,邮件,盗取你的账号,设置购买商品,造成你个人隐私泄露,已经财产安全。

 

 实现

为了能够让所有的视图受到CSRF保护,需要扩展 CsrfProtect模块

from flask_wtf.csrf import CsrfProtect

CsrfProtect(app)

 注意,需要为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响应,我们可以自定义这个错误响应:

from flask_wtf.csrf import CsrfProtect

csrf = CsrfProtect()


@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():

(这里csrf是CsrfProtect()的一个拓展对象)

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

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

AJAX

不用表单,通过ajax发送post请求成为可能,flask 0.9后的版本可用。如果你使用了  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>

无论什么时候发送Ajax POST请求,都要添加X-CSRFToken请求头

 

实现案例

view.py中代码案例

from flask_wtf.csrf import CSRFProtect
CSRFProtect(app)


@app.route("/login", methods=["GET", "POST"])
def login():
    if request.method == "POST":
        # 获取传过来的数据, 这里不是用表单的方式提交,所以用的 request.values.get("key") ,
        # 如果是表单的方式提交数据的话,需要用request.form["key"] 或者 request.form.get("key")
        name = request.values.get("name")
        pwd = request.values.get("pwd")
        # models查询操作,到数据库中查找满足条件的数据,first()返回查询结果的第一条数据,实际是一个aa对象
        flag = aa.query.filter(aa.username == name, aa.password == pwd).first()
        print(flag)
        if flag != None:
            return make_response("{}")
        return make_response("")
    return render_template("login.html")

这里点击登录后,会到aa中去查找是否存在,然后返回不同的response,

login.html中的Ajax代码以及对应的表格,这里我没有使用表单

                var csrftoken = $("meta[name=csrf-token]").attr("content");
                if(flag){
                    //判断账号密码是否匹配
                    $.ajax({
                        url:"/login",
                        type:"POST",
                        dataType:"json",
                        data:{"name":username, "pwd":pwd,},
                        headers:{"X-CSRFToken":csrftoken},
                        success:function (data) {
                            if (data!=null && data!=""){
                                location.href="/index";
                            }else {
                                texta.innerText="账号或密码错误"
                            }
                        },
                        error:function (data) {
                            alert("+++"+data.msg);
                        }
                    });
                }
<table width="500px" border="1" cellspacing="0" cellpadding="0" align="center">
            <meta name="csrf-token" content="{{ csrf_token() }}">
            <tr height="50px">
                <th colspan="2" style="font-size: 30px;" >登录图书管理系统</th>
            </tr>
            <tr>
                <td style="background-color: cornflowerblue;">用户名:</td>
                <td>
                    <input id="username" type="text" name="username" value="">
                </td>
            </tr>
            <tr>
                <td style="background-color: cornflowerblue;">密码:</td>
                <td>
                    <input id="pwd" type="password" name="pwd" value="">
                </td>
            </tr>
            <tr>
                <td colspan="2" align="center">
                    <input type="button" value="登录" onclick="login()"/>
                </td>
            </tr>
            <tr>
                <td colspan="2">
                    <a id="a" style="color: red"></a>
                </td>
            </tr>
        </table>

使用ajax,则必须在其中添加  headers:{"X-CSRFToken":csrftoken},否则就会下图所示错误

会提示CSRF令牌缺失,

这里就是我关于flask中添加CSRF保护后,关于Ajax POST提交问题所遇到的问题,解决方法就是添加X-CSRFToken请求头

 

Python本身并不直接支持Flash架构,因为Flash是一种基于ActionScript的客户端技术,主要用于创建交互式网页内容,而Python更偏向于服务器端语言,如Flask、Django等。如果你想要在Python应用中实现用户登录功能,通常会采用现代的Web框架和安全协议。 例如,使用Flask框架的话,你可以这样做: 1. 安装依赖:首先安装Flask和其他必要的库,如`Flask-SQLAlchemy`用于数据库操作,`Flask-Login`处理用户认证。 ```bash pip install flask flask_sqlalchemy flask_login ``` 2. 实现模型(User Model):定义用户表结构。 ```python from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy() class User(db.Model): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(80), unique=True, nullable=False) password = db.Column(db.String(120), nullable=False) ``` 3. 设置视图函数和路由:创建一个登录页面接收用户名和密码,以及登录验证逻辑。 ```python from flask import request, render_template, redirect, url_for from flask_login import LoginManager, login_user, logout_user, login_required login_manager = LoginManager() login_manager.init_app(app) @login_manager.user_loader def load_user(user_id): return User.query.get(int(user_id)) @app.route('/login', methods=['GET', 'POST']) def login(): if request.method == 'POST': user = User.query.filter_by(username=request.form['username']).first() if user and user.password == request.form['password']: login_user(user) return redirect(url_for('protected')) else: error = "Invalid credentials" return render_template('login.html', error=error) ``` 4. 使用模板(login.html)设计前端登录界面,并链接到受保护的页面(`protected`视图)。 请注意,实际生产环境中,为了安全起见,不应直接在前端显示明文密码,应该使用加密技术存储密码并进行比较。以上是一个简化的示例,实际项目中还需要考虑更多的因素,比如CSRF防护和错误处理等。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值