Python中的CSRF攻击与CSRF令牌绕过
CSRF(Cross-Site Request Forgery)攻击是一种常见的网络攻击方式,攻击者通过伪造用户的身份向目标网站发送请求,以完成某种意外操作,从而达到窃取用户信息或推广垃圾信息等目的。而CSRF令牌是一种预防CSRF攻击的重要手段,目的是确保请求的有效性。
在Python中,我们可以通过如下代码实现CSRF令牌机制:
from flask import Flask, render_template_string, session, request import random, string app = Flask(__name__) app.secret_key = 'my_secret_key' def generate_csrf_token(): if '_csrf_token' not in session: session['_csrf_token'] = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(32)) return session['_csrf_token'] @app.before_request def csrf_protect(): if request.method == 'POST': csrf_token = session.pop('_csrf_token', None) if not csrf_token or csrf_token != request.form.get('_csrf_token'): return render_template_string('Invalid CSRF token') @app.route('/') def index(): csrf_token = generate_csrf_token() return render_template_string(''' <form method="post" action="/"> <input type="hidden" name="_csrf_token" value="{{ csrf_token }}"> <input type="text" name="username" placeholder="Username"><br> <input type="password" name="password" placeholder="Password"><br> <button type="submit">Login</button> </form> ''', csrf_token=csrf_token) if __name__ == '__main__': app.run(debug=True)
在上述代码中,我们通过Flask框架实现了CSRF令牌机制,主要包括以下几个步骤:
- 定义生成CSRF令牌的函数generate_csrf_token,如果不存在令牌则生成一个32位的随机字符串并存储到session中,最后返回令牌;
- 在before_request钩子函数中,判断是否为POST请求,如果是,则获取表单中的CSRF令牌值并与session中存储的令牌值进行比对,如果不一致则说明令牌无效;
- 在index路由函数中,调用generate_csrf_token函数生成令牌并传入模板中,最终将令牌作为隐藏字段添加到表单中。
通过以上步骤,我们实现了CSRF令牌机制,用户在提交表单时必须携带与session中存储的令牌匹配的CSRF令牌方可通过验证。
而CSRF攻击的绕过则通常通过以下几种方式:
- 利用GET请求:CSRF攻击主要针对POST请求,因为GET请求可以直接在URL中携带参数,而POST请求需要通过表单提交数据。所以,攻击者可能会通过构造伪装链接等方式,利用GET请求进行攻击。
- 利用COOKIES:通常情况下,COOKIES是用于存储用户信息的,而CSRF攻击也是利用了COOKIES来伪造用户身份。但是,如果攻击者拥有COOKIES信息,也就意味着他已经黑了用户账号,这种情况下也就可以无限制地发起攻击。
- 利用Referer设置:Referer是HTTP头部的一个字段,用于标识请求来源URL。在一些网站中,可以通过Referer字段来限制CSRF攻击。攻击者可以通过在请求中设置合适的Referer值来绕过该限制。
为了更好地说明CSRF攻击和绕过,我们可以参考以下代码示例:
from flask import Flask, render_template_string, session, request, redirect import random, string app = Flask(__name__) app.secret_key = 'my_secret_key' def generate_csrf_token(): if '_csrf_token' not in session: session['_csrf_token'] = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(32)) return session['_csrf_token'] @app.before_request def csrf_protect(): if request.method == 'POST': csrf_token = session.pop('_csrf_token', None) if not csrf_token or csrf_token != request.form.get('_csrf_token'): return render_template_string('Invalid CSRF token') @app.route('/') def index(): csrf_token = generate_csrf_token() return render_template_string(''' <form method="post" action="/"> <input type="hidden" name="_csrf_token" value="{{ csrf_token }}"> <input type="text" name="username" placeholder="Username"><br> <input type="password" name="password" placeholder="Password"><br> <button type="submit">Login</button> </form> ''', csrf_token=csrf_token) @app.route('/profile') def profile(): if session.get('logged_in'): return 'Welcome ' + session['username'] else: return redirect('/') @app.route('/login', methods=['POST']) def login(): username = request.form['username'] password = request.form['password'] session['username'] = username session['logged_in'] = True return redirect('/profile') @app.route('/logout') def logout(): session.pop('username', None) session.pop('logged_in', None) return redirect('/') if __name__ == '__main__': app.run(debug=True)
在上述示例中,我们实现了一个简单的登录系统,通过用户名和密码登录后可以进入用户资料页面,点击注销按钮即可退出登录。但是,这个系统存在着严重的CSRF攻击漏洞,在攻击者的攻击下,用户的账号信息可能会被篡改。
攻击者可以通过伪造表单数据,利用POST请求来篡改用户的账号信息。具体代码如下:
import requests url = 'http://localhost:5000/login' payload = { 'username': 'pidancode.com', 'password': '123456', '_csrf_token': 'invalid_csrf_token' } headers = { 'Referer': 'http://localhost:5000/' } response = requests.post(url, data=payload, headers=headers) if response.status_code == 200: print(response.content.decode()) else: print('Failed: ', response.status_code)
在上述代码中,我们通过POST请求将伪造的用户名、密码和错误的CSRF令牌发送给目标网站,其中Referer字段为攻击者设置的伪装URL。攻击者想要成功地利用CSRF攻击实现用户账号的篡改,必须绕过目标网站的CSRF令牌验证机制。在本例中,我们设置了一条错误的CSRF令牌,这就足以使攻击失败。而如果我们使用正确的CSRF令牌,攻击就会成功。
当然,这只是一种简单的攻击方式,实际上攻击者可以通过多种方式进行CSRF攻击和绕过。因此,前端和后端开发人员需要共同预防并在系统设计防范时耐心思考。
相关文章