CSRF攻击和防护(3)

7.添加session

逻辑是这样的,如果用户登录,那么就记录到session中,后续所有的操作都需要检查session数据.

# config.py

import os
from datetime import timedelta


# 配置session加密
SECRET_KEY = os.urandom(24)
# 设置超时时间
PERMANENT_SESSION_LIFETIME=timedelta(days=10)
# app.py


# 登录页
class LoginView(views.MethodView):
   def get(self):
       return render_template('login.html')
   def post(self):
       # 验证表单
       form = LoginForm()
       if form.validate_on_submit():
           # 表单验证成功,就跳转到数据库验证
           print('表单验证成功')
           email = form.email.data 
           password = form.password.data
           lifetime = form.lifetime.data
           # 数据库判断
           print(email, password, lifetime)
           exist_user = db.session.query(BankUsers).filter(BankUsers.email==email).filter(BankUsers.password==password).first()
           print(exist_user)
           if exist_user != None:
               if lifetime:
                   session.clear()
                   session['username'] = exist_user.username
                   session.permanent = True
                   return redirect(url_for('personal'))
               else:
                   session.clear()
                   session['username'] = exist_user.username
                   return redirect(url_for('personal'))
           else:
               return render_template('login.html', info=form.errors)
       else:
           return render_template('login.html', info="用户名密码不正确,请注册")

如果点选checkbox,就设置cookie时长,否则关闭浏览器后cookie失效

  • 不点选checkbox
CSRF攻击和防护(3)
10315
  • 点选checkbox
CSRF攻击和防护(3)
10314

8.优化personal

优化显示personal中的数据.

注意:personal.html中应该有接收后端数据的代码

# app.py

# 个人信息页面
@app.route('/personal/')
def personal():
   if session.get('username'None):
       username = session['username']
       balance = db.session.query(BankUsers.balance).filter(BankUsers.username == username).first()
       return render_template('personal.html', username=username, balance=balance)
   else:
       return redirect(url_for('LoginView'))

使用session登录之后,即可查询账户剩余金额

CSRF攻击和防护(3)
10316

9.将session存储在Redis

修改config.py指定保存的类型

# redisModel.py

from redis import StrictRedis

redis = StrictRedis(host='192.168.0.101', port=6379)
# config.py

import os
from datetime import timedelta
from redisModel import redis

DEBUG = True
TEMPLATES_AUTO_RELOAD = True

# 数据库支持
msg = "MySQL+pymysql://root:2008.Cn123@192.168.0.101:3306/flask_csrf_demo"
SQLALCHEMY_DATABASE_URI = msg
SQLALCHEMY_TRACK_MODIFICATIONS = False # 关闭追踪

# 显式关闭CSRF
WTF_CSRF_ENABLED = False

# 配置session加密
SECRET_KEY = os.urandom(24)
# 设置超时时间
PERMANENT_SESSION_LIFETIME=timedelta(days=10)

# session 保存在 redis中
# 指定Session保存类型
SESSION_TYPE = 'redis'
SESSION_USE_SIGNER = True # 加密
SESSION_KEY_PREFIX= 'session'
SESSION_REDIS = redis
# app.py

from flask_session import Session as Fsession

Fsession(app

登录账户后,查看redis ,有session开头的数据,说明成功.

CSRF攻击和防护(3)
10317

10.修改存钱和转账页面

# app.py


# 存钱页面
class SaveMoneyView(views.MethodView):
   def get(self):
       if session.get('username'None):
           return render_template('savemoney.html', user=session['username'])
       else:
           return redirect(url_for('login'))
   def post(self):
       form = SaveMoneyForm()
       if form.validate_on_submit():
           # 如果表单验证成功,则去session中查看 username
           if session.get('username'None):
               add_money = form.add_money.data
               true_user = db.session.query(BankUsers).filter(BankUsers.username == session['username']).first()
               true_user.balance += add_money
               db.session.commit()
               return redirect(url_for('personal', info='转账成功'))
           else:
               return redirect(url_for('login'))
       else:
           return render_template('savemoney.html', info='请输入正确的金额')    

# 转账页面
class TransferView(views.MethodView):
   def get(self):
       if session.get('username'None):
           return render_template('transfer.html', name=session['username'])
       else:
           return redirect(url_for('login'))
   def post(self):
       form = TransferForm()
       if form.validate_on_submit():
           # 表单验证成功后,转入验证session
           if session.get('username'None):
               money = form.transfer.data 
               transfer_name = form.transfer_name.data
               username = session['username']
               true_user = db.session.query(BankUsers).filter(BankUsers.username == username).first()
               # 判断金额是否符合逻辑
               if true_user.balance >= money:
                   true_user.balance -= money
                   # 转账账户
                   transfer_user = db.session.query(BankUsers).filter(BankUsers.username == transfer_name).first()
                   transfer_user.balance += money

                   # 提交事务
                   db.session.commit()
                   return redirect(url_for('personal', info='转账成功'))
               else:
                   return render_template('transfer.html', info='余额不足')
           else:
               return redirect(url_for('login'))
       else:
           return render_template('transfer.html', info=form.errors)

# 退出
@app.route('/logout/')
def logout():
   """删除session"""
   session.clear()
   return render_template('index.html')

注意,以上建立在确实有session的情况下.

验证:注册2个账户,并发起转账操作,查看数据库中数据是否发生变化.

mysql root@192.168.0.101:flask_csrf_demo> select * from bankusers;       
+----+----------------------+------------+------------+-------------+---------+
| id | email                | username   | password   | phone       | balance |
+----+----------------------+------------+------------+-------------+---------+
| 3  | ningwenyan@qq.com    | ningwenyan | 123456789  | 18518506688 |    9000.0  |
| 4  | mytestuser@qq.com    | mytestuser | 123456789  | 18518506688 | 1000.0  |
+----+----------------------+------------+------------+-------------+---------+

11.限制未登录用户

现在已经实现了登录的账户访问的页面的基本情况,但是还有一种情况,那就是没有注册过的 账户, 如果知道URL,也会访问到savemoney.htmltransfer.html页面,为了避免这种情况,我们需要做出限制,让没有登录的账户不能访问我们的相关页面.

views.MethodView中有一个decorators的功能,可以起到装饰器的作用,可以把验证的函数放在这个里面

>>> from flask import views
>>> help(views.MethodView.decorator
# limit.py

from functools import wraps
from flask import redirect,url_for,session

def limit_session(func):
   @wraps(func)
   def wrapper(*args,**kwargs):
       username = session.get('username',None)
       if username:
           return func(*args,**kwargs)
       else:
           session.clear()
           return redirect(url_for('login'))
   return wrapper
# app.py

# 存钱页面
class SaveMoneyView(views.MethodView):
   decorators = [limit_session]
   def get(self):
       if session.get('username'None):
           return render_template('savemoney.html', user=session['username'])
       else:
           return redirect(url_for('login'))
   def post(self):
       form = SaveMoneyForm()
       if form.validate_on_submit():
           # 如果表单验证成功,则去session中查看 username
           if session.get('username'None):
               add_money = form.add_money.data
               true_user = db.session.query(BankUsers).filter(BankUsers.username == session['username']).first()
               true_user.balance += add_money
               db.session.commit()
               return redirect(url_for('personal', info='转账成功'))
           else:
               return redirect(url_for('login'))
       else:
           return render_template('savemoney.html', info='请输入正确的金额')    

# 转账页面
class TransferView(views.MethodView):
   decorators = [limit_session]
   def get(self):
       if session.get('username'None):
           return render_template('transfer.html', name=session['username'])
       else:
           return redirect(url_for('login'))
   def post(self):
       form = TransferForm()
       if form.validate_on_submit():
           # 表单验证成功后,转入验证session
           if session.get('username'None):
               money = form.transfer.data 
               transfer_name = form.transfer_name.data
               username = session['username']
               true_user = db.session.query(BankUsers).filter(BankUsers.username == username).first()
               # 判断金额是否符合逻辑
               if true_user.balance >= money:
                   true_user.balance -= money
                   # 转账账户
                   transfer_user = db.session.query(BankUsers).filter(BankUsers.username == transfer_name).first()
                   transfer_user.balance += money

                   # 提交事务
                   db.session.commit()
                   return redirect(url_for('personal', info='转账成功'))
               else:
                   return render_template('transfer.html', info='余额不足')
           else:
               return redirect(url_for('login'))
       else:
           return render_template('transfer.html', info=form.errors)

当我们删除cookie后,再次访问savemoney.htmltransfer.html页面, 会自动跳转到登录页面.这样保障了数据的安全.

– END –


原文始发于微信公众号(Flask学习笔记):CSRF攻击和防护(3)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由半码博客整理,本文链接:https://www.bmabk.com/index.php/post/36484.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
半码博客——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!