《Python实战进阶》No 10:基于Flask案例的Web 安全性:防止 SQL 注入、XSS 和 CSRF 攻击
第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 SQLAlchemydb = 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 CSRFProtectapp = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secret-key'
csrf = CSRFProtect(app) # 启用全局 CSRF 保护@app.route('/register', methods=['GET', 'POST'])
def register():form = RegistrationForm() # 继承自 FlaskFormif 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, Lengthclass 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 response -
SameSite 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_stringapp = 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}!" # 未转义输出,存在 XSSelse: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.datapassword = 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 注入:原理、攻击流程与防御措施 - Freebuf
- Web 安全头号大敌 XSS 漏洞解决最佳实践 - 腾讯云
- 防止 SQL 注入的四种方案 - CSDN博客
通过本集的学习,相信你已经掌握了如何在 Python Web 应用中防范 SQL 注入、XSS 和 CSRF 攻击的核心技能。下一集我们将进入微服务架构设计的世界,探索如何用 Python 构建高效、可扩展的分布式系统。敬请期待!
相关文章:
《Python实战进阶》No 10:基于Flask案例的Web 安全性:防止 SQL 注入、XSS 和 CSRF 攻击
第10集:Web 安全性:防止 SQL 注入、XSS 和 CSRF 攻击 在现代 Web 开发中,安全性是至关重要的。无论是用户数据的保护,还是系统稳定性的维护,开发者都需要对常见的 Web 安全威胁有深刻的理解,并采取有效的防…...
蓝桥备赛(六)- C/C++输入输出
一、OJ题目输入情况汇总 OJ(online judge) 接下来会有例题 , 根据一下题目 , 对这些情况进行分析 1.1 单组测试用例 单在 --> 程序运行一次 , 就处理一组 练习一:计算 (ab)/c 的值 B2009 计算 (ab)/c …...
企微审批中MySQL字段TEXT类型被截断的排查与修复实践
在MySQL中,TEXT类型字段常用于存储较大的文本数据,但在一些应用场景中,当文本内容较大时,TEXT类型字段可能无法满足需求,导致数据截断或插入失败。为了避免这种问题,了解不同文本类型(如TEXT、M…...
[ISP] AE 自动曝光
相机通过不同曝光参数(档位快门时间 x 感光度 x 光圈大小)控制进光量来完成恰当的曝光。 自动曝光流程大概分为三部分: 1. 测光:点测光、中心测光、全局测光等;通过调整曝光档位使sensor曝光在合理的阈值内࿰…...
小程序画带圆角的圆形进度条
老的API <canvas id"{{canvasId}}" canvas-id"{{canvasId}}" style"opacity: 0;" class"canvas"/> startDraw() {const { canvasId } this.dataconst query this.createSelectorQuery()query.select(#${canvasId}).bounding…...
16. LangChain实战项目2——易速鲜花内部问答系统
需求简介 易束鲜花企业内部知识库如下: 本实战项目设计一个内部问答系统,基于这些内部知识,回答内部员工的提问。 在前面课程的基础上,需要安装的依赖包如下: pip install docx2txt pip install qdrant-client pip i…...
代码的解读——自用
代码来自:https://github.com/ChuHan89/WSSS-Tissue?tabreadme-ov-file 借助了一些人工智能 run_pipeline.sh 功能总结 该脚本用于执行一个 弱监督语义分割(WSSS) 的完整流程,包含三个阶段: Stage1:训…...
蓝桥杯试题:DFS回溯
一、题目要求 输入一个数组n,输出1到n的全排列 二、代码展示 import java.util.*;public class ikun {static List<List<Integer>> list new ArrayList<>();public static void main(String[] args) { Scanner sc new Scanner(System.in);…...
FPGA开发,使用Deepseek V3还是R1(8):FPGA的全流程(简略版)
以下都是Deepseek生成的答案 FPGA开发,使用Deepseek V3还是R1(1):应用场景 FPGA开发,使用Deepseek V3还是R1(2):V3和R1的区别 FPGA开发,使用Deepseek V3还是R1&#x…...
一个py文件搞定mysql查询+Json转换+表数据提取+根据数据条件生成excel文件+打包运行一条龙
import os import argparse import pymssql import json import pandas as pd from datetime import datetime from pandas.io.formats.excel import ExcelFormatter import openpyxl# 投注类型映射字典 BET_MAPPING {1: WIN, 2: PLA, 3: QIN, 4: QPL,5: DBL, 6: TCE, 7: QTT,…...
微服务学习(1):RabbitMQ的安装与简单应用
目录 RabbitMQ是什么 为什么要使用RabbitMQ RabbitMQ的安装 RabbitMQ架构及其对应概念 队列的主要作用 交换机的主要作用 RabbitMQ的应用 通过控制面板操作(实现收发消息) RabbitMQ是什么 RabbitMQ是一个开源的消息队列软件(消息代理…...
【RAG】Embeding 和 Rerank学习笔记
Q: 现在主流Embeding模型架构 在RAG(Retrieval-Augmented Generation)系统中,嵌入模型(Embedding Model) 是检索阶段的核心组件,负责将查询(Query)和文档(Document&#…...
【Delphi】如何解决使用webView2时主界面置顶,而导致网页选择文件对话框被覆盖问题
一、问题描述: 在Delphi 中使用WebView2控件,如果预先把主界面置顶(Self.FormStyle : fsStayOnTop;),此时,如果在Web页面中有使用(<input type"file" id"fileInput" acc…...
【量化金融自学笔记】--开篇.基本术语及学习路径建议
在当今这个信息爆炸的时代,金融领域正经历着一场前所未有的变革。传统的金融分析方法逐渐被更加科学、精准的量化技术所取代。量化金融,这个曾经高不可攀的领域,如今正逐渐走进大众的视野。它将数学、统计学、计算机科学与金融学深度融合&…...
iOS 使用消息转发机制实现多代理功能
在iOS开发中,我们有时候会用到多代理功能,比如我们列表的埋点事件,需要我们在列表的某个特定的时机进行埋点上报,我们当然可以用最常见的做法,就是设置代理实现代理方法,然后在对应的代理方法里面进行上报&…...
16.3 LangChain Runnable 协议精要:构建高效大模型应用的核心基石
LangChain Runnable 协议精要:构建高效大模型应用的核心基石 关键词:LCEL Runnable 协议、LangChain 链式开发、自定义组件集成、流式处理优化、生产级应用设计 1. Runnable 协议设计哲学与核心接口 1.1 协议定义与类结构 #mermaid-svg-PlmvpSDrEUrUGv2p {font-family:&quo…...
Starrocks入门(二)
1、背景:考虑到Starrocks入门这篇文章,安装的是3.0.1版本的SR,参考:Starrocks入门-CSDN博客 但是官网的文档,没有对应3.0.x版本的资料,却有3.2或者3.3或者3.4或者3.1或者2.5版本的资料,不要用较…...
【北京迅为】itop-3568 开发板openharmony鸿蒙烧写及测试-第1章 体验OpenHarmony—烧写镜像
瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工艺,搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码,支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU,可用于轻量级人工…...
Electron一小时快速上手
1. 什么是 Electron? Electron 是一个跨平台桌面应用开发框架,开发者可以使用 HTML、CSS、JavaScript 等 Web 技术来构建桌面应用程序。它的本质是结合了 Chromium 和 Node.js,现在广泛用于桌面应用程序开发。例如,以下桌面应用都使用了 El…...
算法004——盛最多水的容器
力扣——盛最多水的容器点击即可跳转 当我们选择1号线和8号线时,下标为 1 和 8 形成容器的容积的高度是由 较矮的决定的,即下标为 8 的位置; 而宽度则是 1到8 之间的距离,为 8-17,此时容器的容积为 7 * 7 49。 当我…...
Java Web-Filter
Filter 在 Java Web 开发中,Filter(过滤器)是 Servlet 规范中的一个重要组件,它可以对客户端与服务器之间的请求和响应进行预处理和后处理。以下从多个方面详细介绍 Java Web 中的 Filter: 一、概念和作用 概念&…...
LeetCode 热题100 438. 找到字符串中所有字母异位词
LeetCode 热题100 | 438. 找到字符串中所有字母异位词 大家好,今天我们来解决一道经典的算法题——找到字符串中所有字母异位词。这道题在 LeetCode 上被标记为中等难度,要求我们在字符串 s 中找到所有是 p 的异位词的子串,并返回这些子串的…...
DeepSeek-R1训练时采用的GRPO算法数学原理及算法过程浅析
先来简单看下PPO和GRPO的区别: PPO:通过奖励和一个“评判者”模型(critic 模型)评估每个行为的“好坏”(价值),然后小步调整策略,确保改进稳定。 GRPO:通过让模型自己生…...
Qt基于信号量QSemaphore实现的生产者消费者模型
在 Qt 中,信号量(QSemaphore)是一种用于控制对共享资源访问的同步工具。它允许一定数量的线程同时访问共享资源,适合用于生产者-消费者模型。 代码实现 #include <QCoreApplication> #include <QThread> #include &…...
七星棋牌 6 端 200 子游戏全开源修复版源码(乐豆 + 防沉迷 + 比赛场 + 控制)
七星棋牌源码 是一款运营级的棋牌产品,覆盖 湖南、湖北、山西、江苏、贵州 等 6 大省区,支持 安卓、iOS 双端,并且 全开源。这个版本是 修复优化后的二开版本,新增了 乐豆系统、比赛场模式、防沉迷机制、AI 智能控制 等功能&#…...
CSDN博客导出设置介绍
在CSDN编辑博客时,如果想导出保存到本地,可以选择导出为Markdown或者HTML格式。其中导出为HTML时有这几种选项:jekyll site,plain html,plain text,styled html,styled html with toc。分别是什…...
_ 为什么在python中可以当变量名
在 Python 中,_(下划线)是一个有效的变量名,这主要源于 Python 的命名规则和一些特殊的使用场景。以下是为什么 _ 可以作为变量名的原因和常见用途: --- ### 1. **Python 的命名规则** Python 允许使用字母ÿ…...
使用haproxy实现MySQL服务器负载均衡
一、环境准备 主机名IP地址备注openEuler-1192.168.121.11mysql-server-1openEuler-2192.168.121.12mysql-server-2openEuler-3192.168.121.13clientRocky-1192.168.121.51haproxy 二、mysql-server配置 [rootopenEuler-1 ~]# yum install -y mariadb-server [rootopenEuler…...
音视频-WAV格式
1. WAV格式说明: 2. 格式说明: chunkId:通常是 “RIFF” 四个字节,用于标识文件类型。(wav文件格式表示)chunkSize:表示整个文件除了chunkId和chunkSize这 8 个字节外的其余部分的大小。Forma…...
apload-lab打靶场
1.提示显示所以关闭js 上传<?php phpinfo(); ?>的png形式 抓包,将png改为php 然后放包上传成功 2.提示说检查数据类型 抓包 将数据类型改成 image/jpeg 上传成功 3.提示 可以用phtml,php5,php3 4.先上传.htaccess文件࿰…...
