《Python实战进阶》No10:基于Flask案例的Web安全性:防止SQL注入、XSS和CSRF攻击
- 互联网
- 2025-09-16 18:24:02

第10集:Web 安全性:防止 SQL 注入、XSS 和 CSRF 攻击
在现代 Web 开发中,安全性是至关重要的。无论是用户数据的保护,还是系统稳定性的维护,开发者都需要对常见的 Web 安全威胁有深刻的理解,并采取有效的防护措施。本集聚焦于三种最常见的 Web 安全威胁:SQL 注入、跨站脚本攻击(XSS) 和跨站请求伪造(CSRF),通过一个加固前带有漏洞的代码案例,和一个加固后补全漏洞的代码案例,帮助读者深刻认识如何在 Python Web 应用中防范这些攻击。
一、SQL 注入攻击及其防御
1. 什么是 SQL 注入? SQL 注入是一种利用应用程序未能正确过滤用户输入的漏洞,通过注入恶意 SQL 查询语句来操纵数据库的行为。攻击者可以借此获取敏感信息、篡改数据,甚至删除整个数据库[[7]]。
2. 防御 SQL 注入的关键策略
参数化查询:这是最基础也是最有效的防范措施。参数化查询将用户输入的数据与 SQL 命令分开,避免了恶意输入被解释为 SQL 指令[[8]]。# 使用 SQLAlchemy 的参数化查询示例 from sqlalchemy import text query = text("SELECT * FROM users WHERE username = :username") result = db.execute(query, {"username": user_input}) 最小权限原则:限制数据库用户的权限,确保即使攻击者成功注入 SQL 语句,也无法对数据库造成严重破坏[[4]]。输入验证和过滤:对用户输入进行严格的验证,确保其符合预期格式和类型[[3]]。使用 Web 应用防火墙(WAF):部署 WAF 可以检测并阻止潜在的 SQL 注入攻击[[3]]。二、跨站脚本攻击(XSS)及其防御
1. 什么是 XSS 攻击? XSS(Cross-Site Scripting)是指攻击者通过在 Web 页面中插入恶意脚本代码,当其他用户浏览该页面时,恶意脚本会在用户的浏览器上执行,从而窃取用户信息或实施其他恶意行为[[5]]。
2. XSS 的常见类型
存储型 XSS:恶意脚本被永久存储在目标服务器上(如数据库),并通过正常页面加载传播给其他用户。反射型 XSS:恶意脚本通过 URL 参数传递,并在页面加载时直接执行。DOM 型 XSS:攻击发生在客户端,不涉及服务器端的处理。3. 防御 XSS 的关键策略
输入验证:确保用户输入的内容符合预期格式,并拒绝任何包含非法字符的输入[[10]]。输出编码:在将用户输入的内容返回到前端时,对其进行 HTML 编码,防止恶意脚本被执行[[10]]。# 使用 Django 的 escape 函数对输出进行编码 from django.utils.html import escape safe_output = escape(user_input) 启用内容安全策略(CSP):通过 HTTP 头部设置 CSP,限制页面中可以加载的资源来源,减少 XSS 攻击的可能性[[5]]。三、跨站请求伪造(CSRF)及其防御
1. 什么是 CSRF 攻击? CSRF(Cross-Site Request Forgery)是指攻击者诱导用户访问恶意网站,然后利用用户的已登录状态向目标网站发起未经授权的请求。例如,攻击者可能通过伪造表单提交操作,导致用户无意中修改账户信息或转账资金[[6]]。
2. 防御 CSRF 的关键策略
使用 CSRF Token:在表单中嵌入一个随机生成的 Token,并在服务器端验证该 Token 是否合法。这样可以确保请求是由合法用户发起的[[9]]。# Flask-WTF 自动生成 CSRF Token 示例 from flask_wtf.csrf import CSRFProtect app = Flask(__name__) app.config['SECRET_KEY'] = 'your_secret_key' csrf = CSRFProtect(app) 检查 Referer 头部:验证请求是否来自合法的源地址[[9]]。SameSite Cookie 属性:通过设置 Cookie 的 SameSite 属性为 Strict 或 Lax,限制 Cookie 在跨站请求中的发送[[9]]。四、总结与最佳实践
以下是一个基于 Flask 的完整案例,综合运用 SQL 注入、XSS 和 CSRF 的防御技术,并结合知识库中的参考资料进行说明。
案例:用户注册与登录系统(安全加固版) 1. 项目结构 myapp/ ├── app.py # 主程序 ├── models.py # 数据库模型 ├── templates/ │ ├── register.html │ ├── login.html │ └── profile.html └── requirements.txt
2. 核心代码实现
2.1 防止 SQL 注入 使用 SQLAlchemy 的参数化查询,避免直接拼接 SQL 语句(参考 [[3]][[8]])。
# models.py from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy() class User(db.Model): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(80), unique=True, nullable=False) password = db.Column(db.String(120), nullable=False)错误示例(直接拼接 SQL):
# 危险!容易被 SQL 注入 query = f"SELECT * FROM users WHERE username = '{user_input}'"正确示例(参数化查询):
# app.py from models import User @app.route('/login', methods=['POST']) def login(): username = request.form['username'] user = User.query.filter_by(username=username).first() # 安全查询 # ...后续验证逻辑2.2 防止 XSS 攻击 在模板中自动转义用户输入(参考 [[2]][[10]])。
<!-- templates/profile.html --> <!-- 使用 Jinja2 的自动转义功能 --> <p>欢迎, {{ user.username | safe }}!</p> <!-- 错误:禁用转义会引发 XSS --> <p>欢迎, {{ user.username }}!</p> <!-- 正确:默认自动转义 -->手动防御:在视图函数中对输出编码:
from markupsafe import escape @app.route('/profile/<username>') def profile(username): safe_username = escape(username) # 转义特殊字符 return render_template('profile.html', username=safe_username)2.3 防止 CSRF 攻击 使用 Flask-WTF 生成和验证 CSRF Token(参考 [[9]])。
# app.py from flask_wtf.csrf import CSRFProtect app = Flask(__name__) app.config['SECRET_KEY'] = 'your-secret-key' csrf = CSRFProtect(app) # 启用全局 CSRF 保护 @app.route('/register', methods=['GET', 'POST']) def register(): form = RegistrationForm() # 继承自 FlaskForm if form.validate_on_submit(): # 处理注册逻辑 return render_template('register.html', form=form) <!-- templates/register.html --> <form method="POST"> {{ form.hidden_tag() }} <!-- 自动生成 CSRF Token --> {{ form.username.label }} {{ form.username() }} {{ form.password.label }} {{ form.password() }} <input type="submit" value="注册"> </form>3. 综合防御策略
输入验证:使用 WTForms 对用户名和密码格式进行校验。
from wtforms import StringField, PasswordField from wtforms.validators import DataRequired, Length class RegistrationForm(FlaskForm): username = StringField('用户名', validators=[DataRequired(), Length(max=80)]) password = PasswordField('密码', validators=[DataRequired(), Length(min=8)])内容安全策略(CSP) 通过 HTTP 头限制脚本来源(参考 [[5]]):
@app.after_request def set_csp(response): response.headers['Content-Security-Policy'] = "default-src 'self'; script-src 'self'" return responseSameSite Cookie 属性 防止跨站请求携带 Cookie:
app.config['SESSION_COOKIE_SAMESITE'] = 'Lax'4. 测试与验证 SQL 注入测试:尝试输入 ' OR 1=1--,验证是否无法绕过登录。XSS 测试:输入 <script>alert('xss')</script>,验证是否被转义。CSRF 测试:使用 Postman 直接提交表单,验证是否因缺少 Token 被拦截。
以下通过两套正反代码及攻击代码示例,让读者更深刻认识本文内容。
login.html 代码
<!-- templates/login.html --> <!DOCTYPE html> <html> <head> <title>登录</title> </head> <body> <h2>用户登录</h2> <form method="POST"> {{ form.hidden_tag() }} <!-- CSRF Token --> <div> {{ form.username.label }}<br> {{ form.username(size=32) }} </div> <div> {{ form.password.label }}<br> {{ form.password(size=32) }} </div> <div> <input type="submit" value="登录"> </div> </form> </body> </html>完整代码示意:无防护措施的代码及攻击示例 1.1 存在漏洞的代码(SQL 注入 + XSS) # app.py(错误示例) from flask import Flask, request, render_template_string app = Flask(__name__) # 模拟用户数据库 users = { "admin": "admin123" } @app.route('/login', methods=['GET', 'POST']) def login(): if request.method == 'POST': username = request.form['username'] password = request.form['password'] # 危险!直接拼接 SQL 查询(假设使用 SQLite) query = f"SELECT * FROM users WHERE username = '{username}' AND password = '{password}'" # 模拟查询结果(实际场景中可能直接执行 SQL) if username in users and users[username] == password: return f"欢迎,{username}!" # 未转义输出,存在 XSS else: return "登录失败" return render_template_string(''' <form method="POST"> 用户名:<input type="text" name="username"><br> 密码:<input type="password" name="password"><br> <input type="submit" value="登录"> </form> ''') 1.2 攻击示例
SQL 注入攻击: 输入用户名为 admin’ OR ‘1’ = '1,密码任意(假设为 a_random_password),此时完美绕过验证并执行了查询语句:
SELECT * FROM users WHERE username = 'admin' OR '1' = '1' AND password = 'a_random_password'后果:攻击者无需密码即可登录任意账户。
XSS 攻击: 输入用户名为 <script>alert('XSS')</script>,密码任意:
return f"欢迎,{username}!" # 未转义输出后果:恶意脚本在用户浏览器执行,窃取 Cookie 或重定向到钓鱼网站。
完整代码示意:有防护措施的代码及成功防御 2.1 安全加固的代码 # app.py(正确示例) from flask import Flask, request, render_template from flask_wtf.csrf import CSRFProtect from wtforms import StringField, PasswordField, validators from werkzeug.security import check_password_hash from models import User # 假设使用 SQLAlchemy 模型 app = Flask(__name__) app.config['SECRET_KEY'] = 'your-secret-key' csrf = CSRFProtect(app) # 启用 CSRF 保护 class LoginForm(FlaskForm): username = StringField('用户名', [validators.DataRequired()]) password = PasswordField('密码', [validators.DataRequired()]) @app.route('/login', methods=['GET', 'POST']) def login(): form = LoginForm() if form.validate_on_submit(): username = form.username.data password = form.password.data # 使用参数化查询防止 SQL 注入 user = User.query.filter_by(username=username).first() if user and check_password_hash(user.password, password): return render_template('welcome.html', username=escape(username)) # 转义输出 else: return "登录失败" return render_template('login.html', form=form) 2.2 防御效果
SQL 注入防御: 输入 admin’ OR ‘1’ = '1 会被参数化查询自动转义为字符串,无法破坏 SQL 语法。
SELECT * FROM users WHERE username = ''admin' OR '1' = '1'' -- 无效查询XSS 防御: 输入 <script>alert('XSS')</script> 会被 Jinja2 自动转义为:
<script>alert('XSS')</script>浏览器不会执行脚本,仅显示纯文本 。
CSRF 防御: 未携带合法 Token 的请求会被 Flask-WTF 拦截,返回 403 错误 。
总结 攻击类型无防护后果防护措施防护效果SQL 注入绕过登录验证参数化查询攻击失效XSS窃取用户会话输出转义 + CSP脚本被转义CSRF伪造请求操作CSRF Token请求被拦截 5. 总结
通过本案例,我们实现了:
参数化查询(SQLAlchemy)防范 SQL 注入 [[3]][[8]]。模板转义 + CSP 防范 XSS [[2]][[10]]。CSRF Token + SameSite Cookie 防范 CSRF [[9]]。为了构建一个安全的 Web 应用,开发者需要从多个层面入手,结合技术手段和开发习惯来防范上述攻击:
代码层面:始终使用参数化查询、输入验证和输出编码,避免直接拼接用户输入。架构层面:采用最小权限原则,限制数据库用户权限,并部署 WAF 等安全工具。框架支持:利用现代 Web 框架(如 Django、Flask)内置的安全机制,例如 CSRF Token 和 XSS 防护。定期测试:通过渗透测试和代码审计,发现并修复潜在的安全漏洞[[4]]。安全性是一个持续改进的过程。随着攻击手段的不断演变,开发者也需要保持警惕,及时更新知识和技术,确保应用的安全性。
五、扩展阅读与参考资料
参考资料:
Flask 综合案例开发流程REST API 安全设计CSRF 防御最佳实践深入理解 SQL 注入:原理、攻击流程与防御措施 - FreebufWeb 安全头号大敌 XSS 漏洞解决最佳实践 - 腾讯云防止 SQL 注入的四种方案 - CSDN博客通过本集的学习,相信你已经掌握了如何在 Python Web 应用中防范 SQL 注入、XSS 和 CSRF 攻击的核心技能。下一集我们将进入微服务架构设计的世界,探索如何用 Python 构建高效、可扩展的分布式系统。敬请期待!
《Python实战进阶》No10:基于Flask案例的Web安全性:防止SQL注入、XSS和CSRF攻击由讯客互联互联网栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“《Python实战进阶》No10:基于Flask案例的Web安全性:防止SQL注入、XSS和CSRF攻击”