flask内容学习第三天(flak中的csrf跨站请求)

问题一:什么是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)
站点A的逻辑代码示例

 

 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>
站点A的登录界面模拟

 

 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>
站点A的转账模拟

 

 

站点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)
站点B的逻辑代码模拟

 

 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的模拟请求伪造的代码

 

 

备注:B中隐藏的标签会在用户不知道的情况下携带A中的cookie值向A站点发送转账的请求;

posted @ 2018-06-20 19:34  cerofang  阅读(556)  评论(0编辑  收藏  举报