CSRF

  • CSRF全拼为Cross Site Request Forgery,译为跨站请求伪造。
  • CSRF指攻击者盗用了你的身份,以你的名义发送恶意请求。
    • 包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账......
  • 造成的问题:个人隐私泄露以及财产安全。

CSRF攻击示意图

  • 客户端访问服务器时没有同服务器做安全验证

防止 CSRF 攻击

步骤

  1. 在客户端向后端请求界面数据的时候,后端会往响应中的 cookie 中设置 csrf_token 的值
  2. 在 Form 表单中添加一个隐藏的的字段,值也是 csrf_token
  3. 在用户点击提交的时候,会带上这两个值向后台发起请求
  4. 后端接受到请求,以会以下几件事件:
    • 从 cookie中取出 csrf_token
    • 从 表单数据中取出来隐藏的 csrf_token 的值
    • 进行对比
  5. 如果比较之后两值一样,那么代表是正常的请求,如果没取到或者比较不一样,代表不是正常的请求,不执行下一步操作

代码演示

未进行 csrf 校验的 WebA

  • 后端代码实现

    from flask import Flask, render_template, make_response
    from flask import redirect
    from flask import request
    from flask import url_for app = Flask(__name__) @app.route('/', methods=["POST", "GET"])
    def index():
    if request.method == "POST":
    # 取到表单中提交上来的参数
    username = request.form.get("username")
    password = request.form.get("password") if not all([username, password]):
    print('参数错误')
    else:
    print(username, password)
    if username == 'laowang' and password == '1234':
    # 状态保持,设置用户名到cookie中表示登录成功
    response = redirect(url_for('transfer'))
    response.set_cookie('username', username)
    return response
    else:
    print('密码错误') return render_template('temp_login.html') @app.route('/transfer', methods=["POST", "GET"])
    def transfer():
    # 从cookie中取到用户名
    username = request.cookies.get('username', None)
    # 如果没有取到,代表没有登录
    if not username:
    return redirect(url_for('index')) if request.method == "POST":
    to_account = request.form.get("to_account")
    money = request.form.get("money")
    print('假装执行转操作,将当前登录用户的钱转账到指定账户')
    return '转账 %s 元到 %s 成功' % (money, to_account) # 渲染转换页面
    response = make_response(render_template('temp_transfer.html'))
    return response if __name__ == '__main__':
    app.run(debug=True, port=9000) 
  • 前端登录页面代码
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>登录</title>
    </head>
    <body> <h1>我是网站A,登录页面</h1> <form method="post">
    <label>用户名:</label><input type="text" name="username" placeholder="请输入用户名"><br/>
    <label>密码:</label><input type="password" name="password" placeholder="请输入密码"><br/>
    <input type="submit" value="登录">
    </form> </body>
    </html>
  • 前端转账页面代码

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>转账</title>
    </head>
    <body>
    <h1>我是网站A,转账页面</h1> <form method="post">
    <label>账户:</label><input type="text" name="to_account" placeholder="请输入要转账的账户"><br/>
    <label>金额:</label><input type="number" name="money" placeholder="请输入转账金额"><br/>
    <input type="submit" value="转账">
    </form> </body>
    </html>

    运行测试,如果在未登录的情况下,不能直接进入转账页面,测试转账是成功的

攻击网站B的代码

  • 后端代码实现

    from flask import Flask
    from flask import render_template app = Flask(__name__) @app.route('/')
    def index():
    return render_template('temp_index.html') if __name__ == '__main__':
    app.run(debug=True, port=8000)  
  • 前端代码实现
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Title</title>
    </head>
    <body> <h1>我是网站B</h1> <form method="post" action="http://127.0.0.1:9000/transfer">
    <input type="hidden" name="to_account" value="999999">
    <input type="hidden" name="money" value="190000" hidden>
    <input type="submit" value="点击领取优惠券">
    </form> </body>
    </html>

    运行测试,在用户登录网站A的情况下,点击网站B的按钮,可以实现伪造访问

在网站A中模拟实现 csrf_token 校验的流程

  • 添加生成 csrf_token 的函数

    # 生成 csrf_token 函数
    def generate_csrf():
    return bytes.decode(base64.b64encode(os.urandom(48)))
  • 在渲染转账页面的,做以下几件事情:
    • 生成 csrf_token 的值
    • 在返回转账页面的响应里面设置 csrf_token 到 cookie 中
    • 将 csrf_token 保存到表单的隐藏字段中
      @app.route('/transfer', methods=["POST", "GET"])
      def transfer():
      ...
      # 生成 csrf_token 的值
      csrf_token = generate_csrf() # 渲染转换页面,传入 csrf_token 到模板中
      response = make_response(render_template('temp_transfer.html', csrf_token=csrf_token))
      # 设置csrf_token到cookie中,用于提交校验
      response.set_cookie('csrf_token', csrf_token)
      return response
  • 在转账模板表单中添加 csrf_token 隐藏字段

    <form method="post">
    <input type="hidden" name="csrf_token" value="{{ csrf_token }}">
    <label>账户:</label><input type="text" name="to_account" placeholder="请输入要转账的账户"><br/>
    <label>金额:</label><input type="number" name="money" placeholder="请输入转账金额"><br/>
    <input type="submit" value="转账">
    </form>  
  • 运行测试,进入到转账页面之后,查看 cookie 和 html 源代码
  • 在执行转账逻辑之前进行 csrf_token 的校验

    if request.method == "POST":
    to_account = request.form.get("to_account")
    money = request.form.get("money")
    # 取出表单中的 csrf_token
    form_csrf_token = request.form.get("csrf_token")
    # 取出 cookie 中的 csrf_token
    cookie_csrf_token = request.cookies.get("csrf_token")
    # 进行对比
    if cookie_csrf_token != form_csrf_token:
    return 'token校验失败,可能是非法操作'
    print('假装执行转操作,将当前登录用户的钱转账到指定账户')
    return '转账 %s 元到 %s 成功' % (money, to_account)

  运行测试,用户直接在网站 A 操作没有问题,再去网站B进行操作,发现转账不成功,因为网站 B 获取不到表单中的 csrf_token 的隐藏字段,而且浏览器有同源策略,网站B是获取不到网站A的 cookie 的,所以就解决了跨站请求伪造的问题

在 Flask 项目中解决 CSRF 攻击

在 Flask 中, Flask-wtf 扩展有一套完善的 csrf 防护体系,对于我们开发者来说,使用起来非常简单

在 FlaskForm 中实现校验

  • 设置应用程序的 secret_key

    • 用于加密生成的 csrf_token 的值

      app.secret_key = "#此处可以写随机字符串#"
  • 在模板的表单中添加以下代码
<form method="post">
{{ form.csrf_token() }}
{{ form.username.label }} {{ form.username }}<br/>
{{ form.password.label }} {{ form.password }}<br/>
{{ form.password2.label }} {{ form.password2 }}<br/>
{{ form.submit }}
</form>
  • 渲染出来的前端页面为:
 

 

  设置完毕,cookie 中的 csrf_token 不需要我们关心,会自动帮我们设置

单独使用

  • 设置应用程序的 secret_key

    • 用于加密生成的 csrf_token 的值

      app.secret_key = "#此处可以写随机字符串#"
  • 导入 flask_wtf.csrf 中的 CSRFProtect 类,进行初始化,并在初始化的时候关联 app

    from flask.ext.wtf import CSRFProtect
    CSRFProtect(app)
  • 如果模板中有表单,不需要做任何事。与之前一样:

    <form method="post">
    {{ form.csrf_token }}
    ...
    </form>
  • 但如果模板中没有表单,你仍需要 CSRF 令牌:

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

      

Flask模拟实现CSRF攻击的更多相关文章

  1. Flask模拟实现CSRF攻击的方法

    https://www.jb51.net/article/144371.htm https://www.cnblogs.com/888888CN/p/9489345.html http://xiaor ...

  2. day94:flask:Jinjia2模板引擎&flask中的CSRF攻击&Flask-SQLAlchemy的创建模型类和基本的增删改查

    目录 1.Jinjia2模板引擎 1.Jinjia2加载模板并传递数据到模板中 2.Jinjia2的模板语句 3.模板中特有的变量和函数 4.模板中内置的过滤器 5.自定义过滤器 6.模板继承 2.在 ...

  3. 在 Flask 项目中解决 CSRF 攻击

    #转载请留言联系 1. CSRF是什么? CSRF全拼为Cross Site Request Forgery,译为跨站请求伪造. CSRF指攻击者盗用了你的身份,以你的名义发送恶意请求.包括:以你名义 ...

  4. 19、Flask实战第19天:CSRF攻击与防御

    CSRF攻击原理 网站是通过cookie来实现登录功能的.而cookie只要存在浏览器中,那么浏览器在访问这个cookie的服务器的时候,就会自动的携带cookie信息到服务器上去.那么这时候就存在一 ...

  5. Flask基础(17)-->防止 CSRF 攻击

    CSRF CSRF全拼为Cross Site Request Forgery,译为跨站请求伪造. CSRF指攻击者盗用了你的身份,以你的名义发送恶意请求. 包括:以你名义发送邮件,发消息,盗取你的账号 ...

  6. python web框架Flask——csrf攻击

    CSRF是什么? (Cross Site Request Forgery, 跨站域请求伪造)是一种网络的攻击方式,它在 2007 年曾被列为互联网 20 大安全隐患之一,也被称为“One Click ...

  7. flask提交表单验证不通过,以及CSRF攻击原理

    学习表单的问题1. 提交表单时怎么都无法验证通过 记录一下,自己的学习bug,主要是因为在模板中书写渲染的语句时,把CSRF的字段名写错了. 因为在模板中书写一些语句是没有提示的,自己手动敲代码容易出 ...

  8. xss和csrf攻击

    xss(cross site scripting)是一种最常用的网站攻击方式. 一.Html的实体编码 举个栗子:用户在评论区输入评论信息,然后再评论区显示.大概是这个样子: <span> ...

  9. php web开发安全之csrf攻击的简单演示和防范(一)

    csrf攻击,即cross site request forgery跨站(域名)请求伪造,这里的forgery就是伪造的意思.网上有很多关于csrf的介绍,比如一位前辈的文章浅谈CSRF攻击方式,参考 ...

随机推荐

  1. css 盒模型 文档流 几种清除浮动的方法

    盒模型 1.box-sizing: content-box 是普通的默认的一种盒子表现模式 盒子大小为 width + padding + border   content-box:此值为其默认值,其 ...

  2. access与excel

    我们承认,Excel是伟大的,但却又不得不承认,Excel不是万能的,它至少在"多数据表关联"."数据处理自动化"."大量数据的处理"等方面 ...

  3. 菜鸟学习Spring——SpringMVC注解版将URL中的参数转成实体

    一.概述 将URL中参数转成实体在我们项目中用的很多比如界面提交表单请求后台的Contorller的时候通过URL传递了一串参数到后台,后台通过Spring让界面的字段与实体的字段映射来实现给后台的实 ...

  4. linux 中环境变量配置文件说明

    1. 修改/etc/profile文件 特点:所有用户的shell都有权使用你配置好的环境变量 说明:如果你的电脑仅用作开发,建议使用此配置,因为所有用户的shell都有权使用你配置好的环境变量,所以 ...

  5. 超简便的ListView中Adapter的写法

    对于 ListView 的使用,他有两个重点的部分,一个是下拉刷新和加载更多,这个今天我们不讲,另外一个是 BaseAdapter 的使用,这个是今天的主角,BaseAdapter 中又有 ViewH ...

  6. 自动装配(AutoWire)

    根据 autowire 的配置选择装配策略 byName 选择和属性名 name 一致的 bean 进行装配: byType 根据类型选择,如果对应的类型匹配到多个bean,则会报错,如下配置: &l ...

  7. Vue项目中引入mockjs

    前提:创建好的vue项目 前言: 为什么引入mockjs:为了实现前后端分离,开发工作可以异步进行 其他工具:axios 一般的前后端交互过程:前端 --> ajax请求 --> 网络协议 ...

  8. centos下安装lnmp各个版本的几种方法

    首先我们用一种yum的方法安装,我们需要rpm源 默认的版本太低了,手动安装有一些麻烦,想采用Yum安装的可以使用下面的方案: 1.检查当前安装的PHP包 yum list installed | g ...

  9. Struts2的学习-属性驱动和模型驱动

    1.新建空项目,并托管到码云 2.设立maven 3.设置pom.xml 4.建包 5.在java包里建立两个类 package com.nf.entity; public class User { ...

  10. XP环境安装request包报错:离线安装packages: certifi urllib3 idna chardet

    分别下载 request certifi urllib3 idna chardet 安装包 数据包下载地址:https://pypi.org/ 解压到python安装目录 使用cmd命令进入..\py ...