您现在的位置是:首页 > 正文

Flask实现CSRF保护

2024-02-01 04:08:55阅读 1

  参考官方文档

 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请求头

 

网站文章

  • 修改git tag的描述信息

    修改git tag的描述信息

    修改git tag的描述信息message

    2024-02-01 04:08:50
  • C语言实现反序输出、分解质因数、回文数判断、斐波那契数列、素数判断、零钱换整、求兔子总数

    C语言实现反序输出、分解质因数、回文数判断、斐波那契数列、素数判断、零钱换整、求兔子总数

    C语言实现反序输出、分解质因数、回文数判断,斐波那契数列、素数判断、零钱换整、求兔子总数

    2024-02-01 04:08:20
  • 时间旅行的Bug 奇怪的输入Bug

    时间旅行的Bug 奇怪的输入Bug

    他将这个Bug保留在应用程序中,并在用户选择时间旅行时显示一个提示信息,告诉他们实际上并没有进行真正的时间旅行,而只是在虚拟世界中进行了体验。有时候,一些奇怪的输入可能会暴露出我们程序中隐藏的问题,这...

    2024-02-01 04:08:14
  • lansee无法双击进去计算机,局域网搜索LanSee工具,网管员神器

    lansee无法双击进去计算机,局域网搜索LanSee工具,网管员神器

    局域网搜索LanSee工具,十分实用的一款软件,本人特别喜欢用,特别是在查大中型网络故障时,简直就是神器。LanSee集成了局域网搜索功能,可以快速搜索出计算机(包括计算机名、IP地址、MAC地址、所...

    2024-02-01 04:08:06
  • C/C++面试:printf实现原理

    在C/C++中,对函数参数的扫描是从后向前的。C/C++的函数参数值通过压入堆栈的方式来给函数传参数的。 最先压⼊的参数最后出来,在计算机的内存中,数据有 2 块,⼀块是堆,⼀块是栈(函数参数及局部变...

    2024-02-01 04:07:38
  • vue搭建后台系统:点击刷新按钮刷新当前子组件页面 热门推荐

    vue搭建后台系统:点击刷新按钮刷新当前子组件页面 热门推荐

    新手上路:我想要实现的是搭建的后台系统,子页面中点击刷新按钮就会刷新该组件页面,不会闪烁空白 参考该博主的博客:https://blog.csdn.net/qq_16772725/article/details/80467492 我直接参考第三种方法: provide / inject组合 方式 官方文档:https://cn.vuejs.org/v2/api/#provide-inje...

    2024-02-01 04:07:31
  • python闭包与装饰器(5句口诀)

    python闭包与装饰器(5句口诀)

    python闭包与装饰器发现b站有个up主解释得很清晰,推荐大家去看一下这个up主的视频!看完了之后就明白怎么写闭包和装饰器了!(文后附链接)三句口诀理解python函数作用域机制1、作用域,是栋楼,...

    2024-02-01 04:07:00
  • 用 PyQt 打造具有专业外观的 GUI

    用 PyQt 打造具有专业外观的 GUI

      快速创建表单:QFormLayout  如果您一直在创建表单以执行将数据输入数据库等操作,那么QFormLayout适合您。此类将小部件布置为两列布局。第一列通常显示描述预期输入的标签,第二列通常...

    2024-02-01 04:06:52
  • Java项目:企业官方平台(java+SSM+HTML+JavaScript+jsp+mysql)

    Java项目:企业官方平台(java+SSM+HTML+JavaScript+jsp+mysql)

    源码获取:俺的博客首页 "资源" 里下载!项目介绍管理员角色包含以下功能:登录,首页,写公司资讯,评论审核,公司资讯信息管理,公司资讯类别信息管理,添加导航,导航信息管理,评论信息管理,修改个人信息,...

    2024-02-01 04:06:46
  • GIT与SVN的区别以及SVN转GIT

    公司部分项目开始使用的SVN,需要通过SVN转成GIT,通过查询可以用git的svn命令,不过在培训时候找到一些svn与git的区别:分布式文件系统,每个人都有完整的;分支对SVN来说是完整目录,建立分支需要重新配置,GIT建立分支相当简单;GIT可以离线查看log日志;SVN提交实际提交到中央仓库,而GIT实际提交到本地仓库;GIT没有全局版本号,需要手工打标签;

    2024-02-01 04:06:38