如何使用Python实现跨站请求伪造的攻击与防御
跨站请求伪造(CSRF)是一种网络攻击方式,攻击者利用受害者在已登录的情况下,通过伪造的请求来执行恶意的操作,例如转账、更改密码等。本篇文章将介绍如何使用Python实现CSRF攻击和防御。
一、CSRF攻击
1.攻击原理
由于受害者已经登录了某个网站,那么该网站的Cookie值已经被存储在受害者浏览器中。攻击者可以伪造一个请求,将该请求发送给受害者,当受害者打开该请求时,该请求将在受害者的浏览器中被执行。此时,由于该请求携带的是伪造的Cookie,因此该请求被认为是合法的,网站无法区分该请求是受害者自己发起的,还是攻击者伪造的。
2.攻击过程
攻击过程如下:
(1)攻击者构造一个包含攻击代码的页面,并将该页面发送给受害者。
(2)当受害者接收到该页面时,会自动执行页面里的攻击代码。
(3)攻击代码会构造一个请求,该请求中包含了攻击者所期望的操作。
(4)请求被发送至目标服务器,由于该请求包含了受害者的Cookie值,因此服务器会误认为该请求是合法的,并执行攻击者所期望的操作。
3.攻击代码
攻击代码如下:
import requests def csrf_attack(): # 将攻击代码放在一个页面中,并将该页面发送给受害者。 url = 'http://www.pidancode.com/attack.html' header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36'} response = requests.get(url, headers=header) print(response.text)
攻击代码的作用是构造一个包含攻击请求的页面,并将该页面发送给受害者。在实际攻击中,攻击者可能会通过社交工程等手段来让受害者打开该页面。
4.攻击演示
为了演示攻击过程,我们可以构造一个被攻击的网站(这里以模拟登录的网站为例)。
攻击网站代码:
from flask import Flask, request, render_template, session, redirect, url_for app = Flask(__name__) app.secret_key = 'pidancode' @app.route('/', methods=['GET', 'POST']) def login(): if request.method == 'POST': username = request.form['username'] password = request.form['password'] # 简单模拟登录功能,当用户名为'pidancode',密码为'123456'时登录成功。 if username == 'pidancode' and password == '123456': session['logged_in'] = True return redirect(url_for('home')) return render_template('login.html') @app.route('/home') def home(): if 'logged_in' in session: return 'Welcome to Pidancode.com!' else: return redirect(url_for('login')) if __name__ == '__main__': app.run(debug=True)
登录页面:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Login</title> </head> <body> <form method="POST" action=""> <label>Username:</label> <input type="text" name="username"> <br> <label>Password:</label> <input type="password" name="password"> <br> <input type="submit" value="Login"> </form> </body> </html>
当用户名为'pidancode',密码为'123456'时,登录成功,并显示'Welcome to Pidancode.com!'。
运行攻击网站,然后在另一个窗口中运行攻击代码,具体过程如下:
(1)使用浏览器访问攻击网站,输入正确的用户名和密码,成功登录。
(2)使用同一浏览器访问攻击页面(attack.html),攻击代码自动执行。
(3)在攻击网站中会发现自动执行了一个注销登录的操作。
(4)此时,在攻击页面中再次访问攻击网站(http://localhost:5000/home),发现已经退出登录。说明攻击成功。
二、CSRF防御
1.防御原理
防御CSRF攻击的方法很多,其中最常见的一种是使用验证码。当受害者发送一个请求时,系统会要求受害者先输入验证码,如果验证通过,则系统才会处理该请求,否则该请求将被拒绝。
2.防御代码
防御CSRF攻击的代码如下所示:
from flask import Flask, request, render_template, session, redirect, url_for import string, random app = Flask(__name__) app.secret_key = 'pidancode' @app.route('/', methods=['GET', 'POST']) def login(): if request.method == 'POST': username = request.form['username'] password = request.form['password'] # 简单模拟登录功能,当用户名为'pidancode',密码为'123456'时登录成功。 if username == 'pidancode' and password == '123456': session['logged_in'] = True session['csrf_token'] = ''.join(random.choice(string.ascii_lowercase + string.ascii_uppercase + string.digits) for x in range(32)) return redirect(url_for('home')) return render_template('login.html') @app.route('/home', methods=['GET', 'POST']) def home(): if 'logged_in' in session: if request.method == 'POST': # 验证CSRF Token,如果验证不通过,则拒绝该请求。 if request.form.get('csrf_token') != session.get('csrf_token'): return 'Error: Invalid CSRF Token' # 处理正确的请求。 operation = request.form.get('operation') if operation == 'logout': session.pop('logged_in', None) session.pop('csrf_token', None) return redirect(url_for('login')) else: return 'Error: Invalid Operation' # 防御CSRF攻击的核心代码,插入一个CSRF Token。 session['csrf_token'] = ''.join(random.choice(string.ascii_lowercase + string.ascii_uppercase + string.digits) for x in range(32)) return render_template('home.html', csrf_token=session['csrf_token']) else: return redirect(url_for('login')) if __name__ == '__main__': app.run(debug=True)
在登录成功后,为了防御CSRF攻击,我们会创建一个CSRF Token,并将该Token存储在用户的会话中,以便在受到请求时进行验证。
当用户发送一个带有操作数据的POST请求时,我们会从前端获取到该请求中的CSRF Token,并根据前端提供的Token来验证该请求。如果验证通过,则继续进行数据处理。
另外,在每次用户访问主页时,都需要重新生成一个CSRF Token,并将该Token插入到网页中,以保证每个请求都是唯一的。
3.防御演示
在使用防御代码后,可以复现上述攻击流程:
(1)使用浏览器访问攻击网站,输入正确的用户名和密码,成功登录。
(2)使用同一浏览器访问攻击页面(attack.html),攻击代码自动执行。
(3)攻击者期望的注销登录操作没有被执行,并且在攻击页面中访问http://localhost:5000/home,收到了'Error: Invalid CSRF Token'消息,说明请求被拒绝。
这表明,我们的CSRF防御代码已经成功地防御了该攻击。
相关文章