问题一:什么是csrf?
英文全称Cross Site Request Forgery(跨站请求伪造);
通俗来讲就是攻击者盗用你的身份,冒用你的名义发出恶意请求,包括发送邮件,电话信息,甚至于转账或者是购买虚拟货币;
csrf攻击的示意图()
CSRF攻击的原理:
1,用户向服务器端发送请求登录信息,服务器端会在用户的浏览器上设置A站点的cookie值;
2,用户在未清除cookie的情况下,在B站点中点击向隐藏的向A站点发送请求的标签,在用户不知情的情况下向A站点发送请求;
3;若A站点在未进行csrftoken验证的情况下,B站点伪造过来的请求就会通过服务器的验证,从而进行下一步的操作。
防止CSRF攻击的方法:
1,前端页面发送请求数据的时候,后端会想cookies上设置一串随机字符串(csrf_token值);
2,在form表单中将设置一个隐藏的字段,值与在cookies中设置的相同(csrf_token值);
3,在用户点击提交的时候,客户端会同时将两个值发送到后端程序;
4,后端接收到客户端的请求之后,会做出一下几个动作
1,从cookies中将csrf_token值取出来;
2,将forn表单中的csrf_token值出来;
3,将两个随机字符串做对比;
5,相同就就表明是用户自己发送过来的请求,不相同就表示是伪造的的用户请求。
代码实例

1 import base64 2 import os 3 from _curses import flash 4 5 from flask import Flask, render_template, make_response 6 from flask import redirect 7 from flask import request 8 from flask import url_for 9 10 app = Flask(__name__) 11 12 13 @app.route('/', methods=["POST", "GET"]) 14 def index(): 15 if request.method == "POST": 16 # 取到表单中提交上来的参数 17 username = request.form.get("username") 18 password = request.form.get("password") 19 20 if not all([username, password]): 21 print('参数错误') 22 else: 23 print(username, password) 24 if username == 'laowang' and password == '1234': 25 # 状态保持,设置用户名到cookie中表示登录成功 26 response = redirect(url_for('transfer')) 27 response.set_cookie('username', username) 28 return response 29 else: 30 print('密码错误') 31 32 return render_template('temp_login.html') 33 34 35 @app.route('/transfer', methods=["POST", "GET"]) 36 def transfer(): 37 # 从cookie中取到用户名 38 username = request.cookies.get('username', None) 39 # 如果没有取到,代表没有登录 40 if not username: 41 return redirect(url_for('index')) 42 43 if request.method == "POST": 44 to_account = request.form.get("to_account") 45 money = request.form.get("money") 46 # 取到表单中的token 47 form_csrf_token = request.form.get('csrf_token') 48 # cookie中的token 49 cookie_csrf_token = request.cookies.get('csrf_token', "") 50 51 # 做校验。如果校验成功,再进行转账逻辑 52 if form_csrf_token != cookie_csrf_token: 53 return "非法请求" 54 55 print('假装执行转账操作,将当前登录用户的钱转账到指定账户') 56 return '转账 %s 元到 %s 成功' % (money, to_account) 57 58 csrf_token = generate_csrf() 59 # 渲染转换页面 60 response = make_response(render_template('temp_transfer.html', csrf_token=csrf_token)) 61 # 往cookie中添加csrf_token 62 response.set_cookie('csrf_token', csrf_token) 63 return response 64 65 66 # 生成 csrf_token 67 def generate_csrf(): 68 return bytes.decode(base64.b64encode(os.urandom(48))) 69 70 71 if __name__ == '__main__': 72 app.run(debug=True, port=9000)

1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>登录</title> 6 </head> 7 <body> 8 9 <h1>我是网站A,登录页面</h1> 10 11 <form method="post"> 12 <label>用户名:</label><input type="text" name="username" placeholder="请输入用户名"><br/> 13 <label>密码:</label><input type="password" name="password" placeholder="请输入密码"><br/> 14 <input type="submit" value="登录"> 15 </form> 16 17 </body> 18 </html>

1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>转账</title> 6 </head> 7 <body> 8 <h1>我是网站A,转账页面</h1> 9 10 <form method="post"> 11 <input type="hidden" name="csrf_token" value="{{ csrf_token }}"> 12 <label>账户:</label><input type="text" name="to_account" placeholder="请输入对方账户"><br/> 13 <label>金额:</label><input type="number" name="money" placeholder="请输入转账金额"><br/> 14 <input type="submit" value="转账"> 15 </form> 16 17 </body> 18 </html>
站点B的逻辑代码

1 from flask import Flask 2 from flask import render_template 3 4 app = Flask(__name__) 5 6 7 @app.route('/') 8 def index(): 9 return render_template('temp_index.html') 10 11 12 if __name__ == '__main__': 13 app.run(debug=True, port=8000)

1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 </head> 7 <body> 8 9 <h1 style="background: red">我是网站B</h1> 10 11 <form method="post" action="http://127.0.0.1:9000/transfer"> 12 <input type="hidden" name="to_account" value="999999"> 13 <input type="hidden" name="money" value="190000"> 14 <input type="submit" value="点击领取优惠券"> 15 </form> 16 17 </body> 18 </html>
备注:B中隐藏的标签会在用户不知道的情况下携带A中的cookie值向A站点发送转账的请求;