flask13-模拟CSRF攻击
CSRF
CSRF全拼为Cross Site Request Forgery,译为跨站请求伪造。
CSRF指攻击者盗用了你的身份,以你的名义发送恶意请求。
包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账......
造成的问题:个人隐私泄露以及财产安全。
CSRF攻击示意图
客户端访问服务器时没有同服务器做安全验证
防止 CSRF 攻击
步骤
在客户端向后端请求界面数据的时候,后端会往响应中的 cookie 中设置 csrf_token 的值
在 Form 表单中添加一个隐藏的的字段,值也是 csrf_token
在用户点击提交的时候,会带上这两个值向后台发起请求
后端接受到请求,以会以下几件事件:
从 cookie中取出 csrf_token
从 表单数据中取出来隐藏的 csrf_token 的值
进行对比
如果比较之后两值一样,那么代表是正常的请求,如果没取到或者比较不一样,代表不是正常的请求,不执行下一步操作
以下使用代码模拟实现webB攻击webA
目录结构:
webA
from flask import Flask, render_template, request, make_response, redirect, url_for, flash
import base64
import os
app = Flask(__name__)
app.secret_key = 'sdfg'
def generate_token():
return base64.b64encode(os.urandom(48)).decode()
# 根节点-登录页
@app.route('/', methods=["GET", "POST"])
def index():
if request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')
if not all([username, password]):
flash("请输入用户名和密码")
return render_template("html/03-login.html")
# 判断用户名和密码是否正确
if username != "laowang" or password != "123456":
flash("用户名和密码错误")
return render_template("html/03-login.html")
resp = make_response(redirect(url_for('transfer')))
resp.set_cookie('username', username)
return resp
return render_template('html/03-login.html')
# /transfer 转账页面
@app.route('/transfer', methods=["GET", "POST"])
def transfer():
# if判断:如果没有登录,重定向到登录页
username = request.cookies.get('username')
if not username:
return redirect(url_for('index'))
if request.method == 'POST':
# 去做转账的逻辑
# 取出参数
to_account = request.form.get('to_account')
money = request.form.get('money')
# 从表单中取出来隐藏随机值
form_token = request.form.get('token')
# 再从 cookie 中取出随机值
cookie_token = request.cookies.get('cookie_token')
if not all([to_account, money]):
flash("请完整输入参数")
return render_template('html/03-transfer.html')
if form_token != cookie_token:
return '非法请求'
# 执行转账操作
print("假装执行转账操作,转给 %s, 转 %s" % (to_account, money))
return "假装执行转账操作,转给 %s, 转 %s" % (to_account, money)
# 生成随机值
token = generate_token()
# 将渲染模板的操作封装成响应
resp = make_response(render_template('html/03-transfer.html', token=token))
# 再存一份到 webB 不能取到的地方
resp.set_cookie('cookie_token', token)
return resp
if __name__ == '__main__':
app.run(host='0.0.0.0', debug=True)
webB
from flask import Flask,render_template
app = Flask(__name__)
@app.route('/', methods=['get', 'post'])
def index():
return render_template('html/03-beat.html')
if __name__ == '__main__':
app.run(port=9001)
03-login.html
webA_login page
我是 WebA 的登录页面
{% for message in get_flashed_messages() %}
{{ message }}
{% endfor %}