page contents

Python 代码审计实战指南:从漏洞原理到防御策略

在 Web 安全领域,Python 凭借其简洁高效的特性成为主流开发语言之一,但随之而来的安全问题也日益凸显。无论是 XSS、SQL 注入等传统漏洞,还是反序列化、沙箱逃逸等 Python 特有的风险,都可能成为攻击者的突破口。

attachments-2025-09-GonV6Y3J68d0a4869d49f.png在 Web 安全领域,Python 凭借其简洁高效的特性成为主流开发语言之一,但随之而来的安全问题也日益凸显。无论是 XSS、SQL 注入等传统漏洞,还是反序列化、沙箱逃逸等 Python 特有的风险,都可能成为攻击者的突破口。

本文原文发布于东方隐侠安全团队的纷传圈子“隐侠安全客栈”(本文末查看原文可跳转),因内容过多,在这里提炼整理了重点的常见 Python 安全漏洞的审计思路与防御方案,帮助开发者和安全工程师建立完整的代码安全审计体系。

01跨站脚本攻击(XSS):模板引擎的 "信任危机"

XSS 的核心是恶意 JavaScript 代码被浏览器解析执行,在 Python Web 开发中,漏洞往往出现在数据输出环节。

审计关键节点:

输出点排查搜索直接拼接 HTML 的代码(如return f"<html>{user_input}</html>")、模板渲染函数(render_template)及 JSON 响应中包含 HTML 的场景。

输入源追溯确认输出变量是否来自用户可控数据(URL 参数、表单、Cookie、数据库存储的用户内容)。

转义机制检查

直接拼接 HTML 时,是否使用html.escape()进行转义;

模板引擎中,是否滥用Markup对象或|safe过滤器(如 Jinja2 中{{ user_input | safe }}会禁用自动转义)。

典型漏洞案例:

# Flask + Jinja2 危险示例from flask import Flask, requestfrom markupsafe import Markupapp = Flask(__name__)@app.route('/search')def search():    keyword = request.args.get('q', '')    safe_keyword = Markup(keyword)  # 错误标记为"安全"    return render_template('search.html', safe_keyword=safe_keyword)

模板中{{ safe_keyword }}会直接输出恶意代码,而{{ keyword }}因默认转义是安全的。

防御方案:

禁止手动拼接 HTML,依赖模板引擎的自动转义机制;

如需输出 HTML,使用严格的白名单过滤(如只允许<b> <i>等标签),而非直接标记为安全;

对用户输入的 HTML 内容,使用bleach等库进行净化。

02路径遍历:从文件下载到系统入侵

路径遍历漏洞允许攻击者访问预期目录外的文件(如/etc/passwd),核心是用户输入未被正确过滤就用于文件操作。

审计关键节点:

危险函数定位搜索open()、os.open()、send_file()等文件操作函数,重点检查其路径参数。

输入净化验证确认用户输入是否经过规范化(os.path.normpath())和白名单校验(路径是否在允许的基目录内)。

典型漏洞代码:

# Flask 危险的文件下载from flask import Flask, request, send_fileimport osapp = Flask(__name__)BASE_DIR = "/var/www/uploads"@app.route('/download')def download():    filename = request.args.get('filename')    file_path = os.path.join(BASE_DIR, filename)  # 直接拼接用户输入    return send_file(file_path)  # 无校验,可通过../../访问敏感文件

修复方案:

def download_safe():    filename = request.args.get('filename')    file_path = os.path.join(BASE_DIR, filename)    normalized_path = os.path.normpath(file_path)  # 解析../    # 关键:验证路径是否在基目录内    if not normalized_path.startswith(BASE_DIR):        return "禁止访问", 403    return send_file(normalized_path)

03反序列化漏洞:pickle/yaml 的 "潘多拉魔盒"

按Python 的序列化机制(如 pickle、yaml、jsonpickle)若处理不可信数据,可能导致远程代码执行,这是 Python 生态中最危险的漏洞类型之一。

审计关键节点:

危险库调用搜索pickle.load()、yaml.load()、jsonpickle.decode()等函数。

数据来源确认检查反序列化的参数是否来自用户输入(上传文件、HTTP 请求体、数据库存储的不可信数据)。

典型漏洞代码:

# 使用pickle反序列化用户输入(高危)import picklefrom flask import Flask, requestapp = Flask(__name__)@app.route('/restore', methods=['POST'])def restore():    data = request.data  # 用户可控数据    obj = pickle.loads(data)  # 直接反序列化,触发恶意代码    return "恢复成功"

防御方案:

优先使用 JSON 等安全格式,避免 pickle/yaml 处理不可信数据;

若必须使用,对数据进行加密签名(如 HMAC),验证完整性后再反序列化;

升级依赖库至最新版本,禁用危险功能(如yaml.safe_load()替代yaml.load())。

04SQL 注入:ORM 也会 "翻车"

即使使用 ORM 框架(如 Django ORM、SQLAlchemy),若滥用原始 SQL 或动态拼接查询,仍可能导致 SQL 注入。审计关键节点:

查询构造方式搜索字符串拼接的 SQL(如f"SELECT * FROM users WHERE name='{name}'")、raw()/extra()等原生 SQL 方法。

参数化查询检查确认是否使用 ORM 的参数绑定(如cursor.execute("SELECT * FROM users WHERE id=?", (user_id,)))。

典型漏洞代码:

# Django 危险的查询from django.db import connectionfrom django.http import HttpResponsedef search(request):    username = request.GET.get('username')    # 直接拼接SQL,存在注入风险    with connection.cursor() as cursor:        cursor.execute(f"SELECT * FROM users WHERE username='{username}'")        results = cursor.fetchall()    return HttpResponse(results)

修复方案:

使用 ORM 的参数化查询:User.objects.filter(username=username);

必须用原生 SQL 时,使用参数绑定:cursor.execute("SELECT * FROM users WHERE username=%s", [username]);

避免将用户输入直接作为表名、字段名(如需,使用严格的白名单)。

05命令注入:subprocess 的 "致命诱惑"

当用户输入被拼接到系统命令中并执行(如subprocess.call(cmd, shell=True)),可能导致任意命令执行。

审计关键节点:

危险函数定位搜索os.system()、subprocess.call()(尤其带shell=True参数)、exec()等。

输入拼接检查确认命令字符串是否包含用户可控内容,是否未经过滤直接拼接。

典型漏洞代码:

# 视频转码服务中的命令注入import subprocessfrom flask import requestdef transcode():    filename = request.args.get('file')    # 直接拼接用户输入到命令中    cmd = f"ffmpeg -i {filename} output.mp4"    subprocess.call(cmd, shell=True)  # shell=True 会解析特殊字符    return "转码完成"

攻击者传入; rm -rf / #会删除系统文件。

防御方案:

禁止使用shell=True,通过参数列表传递命令:subprocess.call(['ffmpeg', '-i', filename, 'output.mp4']);

对用户输入进行严格白名单校验(如只允许a-zA-Z0-9_.等字符);

必要时使用shlex.quote()转义特殊字符(仅作为最后手段)。

06框架特定漏洞:以 Django 为例

主流框架虽内置安全机制,但配置或使用不当仍会产生漏洞,以 Django 为例:

1. URL 跳转漏洞旧版本is_safe_url()函数对特殊格式 URL(如http:123456789,十进制 IP)解析错误,导致恶意跳转。2. 调试页面 XSS开启DEBUG=True时,数据库异常信息(含用户输入)未转义直接显示在错误页面,触发 XSS。3. CSRF 绕过错误重写DeleteView的get方法为return self.post(...),导致 GET 请求执行删除操作,绕过 CSRF 验证。

07代码审计最佳实践

1. 建立审计清单:针对本文提到的漏洞,整理关键审计点(如反序列化关注pickle.loads,路径遍历关注os.path.join)。

2. 自动化工具辅助:使用bandit(Python 代码安全扫描工具)快速定位高危函数:

bandit -r project_dir/  # 扫描项目中的安全问题

3. 结合业务场景:审计需结合功能逻辑,例如文件上传功能重点查路径遍历,用户搜索功能重点查 XSS 和 SQL 注入。

4. 版本依赖检查:使用safety检查依赖库的已知漏洞:

safety check  # 检测已安装库的安全问题

Python 代码审计的核心是追踪用户输入的全生命周期:从输入源到处理逻辑,再到输出点,确保每一步都经过严格验证。无论是原生 Python 特性(如 pickle)还是框架功能(如 Django 模板),过度信任或误用都可能引入风险。

将安全审计融入开发流程(如 Code Review 环节),配合自动化工具和持续学习,才能有效抵御日益复杂的攻击手段。

更多相关技术内容咨询欢迎前往并持续关注好学星城论坛了解详情。

想高效系统的学习Python编程语言,推荐大家关注一个微信公众号:Python编程学习圈。每天分享行业资讯、技术干货供大家阅读,关注即可免费领取整套Python入门到进阶的学习资料以及教程,感兴趣的小伙伴赶紧行动起来吧。

attachments-2022-05-rLS4AIF8628ee5f3b7e12.jpg

你可能感兴趣的文章

相关问题

0 条评论

请先 登录 后评论
小柒
小柒

2204 篇文章

作家榜 »

  1. 轩辕小不懂 2403 文章
  2. 小柒 2204 文章
  3. Pack 1375 文章
  4. Nen 576 文章
  5. 王昭君 209 文章
  6. 文双 71 文章
  7. 小威 64 文章
  8. Cara 36 文章