Python tarfile 解包怎样限制链接路径
如果 Python 程序要解包来源不完全可信的 tar 文件,建议在 Python 3.12 及以上显式传入 filter="data",再用一个自定义过滤器把符号链接和硬链接全部跳过。这样既能限制绝对路径、目标目录外路径和特殊文件,也能把“链接是否允许”变成明确的业务策略,而不是依赖运行环境的默认值。
官方文档:https://docs.python.org/3/library/tarfile.html
只检查成员名称里的 .. 还不够。链接的目标、目标目录的真实路径和特殊文件类型都要纳入解包策略;发生过滤异常后,目标目录可能只解出了一部分内容,不能把它当成完整结果继续使用。
- Python 3.12 引入
extract()和extractall()的filter参数。 filter="data"会拒绝绝对路径、越界链接和设备文件,并限制部分元数据。- 如果业务根本不需要链接,额外返回
None跳过符号链接和硬链接更直观。 - Python 3.14 起默认过滤器改为
data,但显式写出策略有助于兼容 3.12、3.13 和代码审查。
先区分“路径越界”和“链接不允许”
tar 成员至少有两层需要处理:成员自身的名字,以及符号链接或硬链接的目标。成员名字为绝对路径、规范化后落到目标目录之外,属于路径边界问题;链接目标可以把一个看似位于解包目录里的条目指向别处,属于链接边界问题。两者不是同一个判断,不能只用字符串前缀或只查找 ../。
Python 官方的 data 过滤器已经覆盖常见的数据包场景:拒绝绝对路径、拒绝解析后落到目标目录外的链接、拒绝设备文件,并收紧权限和所有者元数据。若业务需要保留内部软链接,应先使用这一层,再在自定义过滤器中允许明确的例外。

先显式使用 data 过滤器
对于普通数据包、上传附件或构建产物,最小改动是给 extractall() 明确传入 filter="data"。这不会把 tar 解包变成完整的恶意文件检测器,但能把标准库已经定义的路径、链接和特殊文件限制应用到当前调用点。
from pathlib import Path
import tarfile
archive_path = Path("incoming/package.tar.gz")
target_dir = Path("work/unpacked")
target_dir.mkdir(parents=True, exist_ok=True)
try:
with tarfile.open(archive_path, mode="r:*") as archive:
# 显式选择数据包策略,避免依赖不同 Python 版本的默认值。
archive.extractall(path=target_dir, filter="data")
except tarfile.FilterError as exc:
# 过滤失败后目录可能只有部分内容,后续流程不要继续读取它。
print(f"拒绝解包成员:{exc}")
raise
这里的 r:* 允许按归档头自动识别常见压缩格式;真正决定链接和路径边界的是 filter 参数。FilterError 表示成员被策略拒绝,异常发生后应删除或隔离 target_dir,再由上层决定是否重试。
不需要链接时,用自定义过滤器全部跳过
如果解出来的是源码包、数据交换包或临时构建输入,通常不需要保留软链接和硬链接。可以先调用官方 data_filter(),再对返回的 TarInfo 检查类型;返回 None 表示跳过当前成员。这样不会重新实现路径规范化和越界判断。
from pathlib import Path
import shutil
import tarfile
def regular_files_only(member: tarfile.TarInfo, destination: str):
# 先复用官方规则,处理绝对路径、越界链接和特殊文件。
safe_member = tarfile.data_filter(member, destination)
if safe_member is None:
return None
# 当前业务只接收目录和普通文件,不保留软链接或硬链接。
if safe_member.issym() or safe_member.islnk():
return None
return safe_member
archive_path = Path("incoming/data.tar")
target_dir = Path("work/data")
if target_dir.exists():
# 清掉上一次失败留下的半成品,避免新旧文件混在一起。
shutil.rmtree(target_dir)
target_dir.mkdir(parents=True)
try:
with tarfile.open(archive_path, mode="r:*") as archive:
# 自定义过滤器只增加“禁用链接”这一条业务规则。
archive.extractall(target_dir, filter=regular_files_only)
except tarfile.FilterError as exc:
# 解包失败时不把半成品目录交给后续业务。
shutil.rmtree(target_dir, ignore_errors=True)
raise RuntimeError("tar 包未通过解包策略") from exc
过滤器接收当前成员和目标目录路径,每个成员解包前都会调用。data_filter() 可能直接抛出 FilterError,而 issym() 与 islnk() 则负责表达“本业务不接受任何链接”。如果确实需要内部链接,不要简单删除这两个判断,而应给允许的目标建立更窄的规则。

链接路径限制应放在解包前的过滤点
extractall() 的过滤器是在每个成员真正落盘前调用的,适合做“允许、修改或拒绝”决策。相比先调用 getmembers() 扫一遍再解包,过滤点能在当前文件系统状态下处理成员,也不会把同一组 TarInfo 对象的修改意外带到后续操作。
但过滤器不是资源配额系统:它不会自动限制归档展开后的总字节数、文件数量、单文件大小或压缩炸弹风险。面对外部上传包,还要在业务层设置上传大小、成员数量、总解包预算,并把解包放到权限较低的隔离目录中。
兼容 Python 版本并处理半成品
filter 参数从 Python 3.12 开始提供,Python 3.14 起默认值改为 data。如果项目仍支持 3.11 或更早版本,直接传入 filter 会触发参数不兼容;更稳妥的做法是升级运行时,或者在旧版本使用经过充分审查的独立解包实现,不要假装旧版本拥有同样的标准库策略。
异常恢复也要单独设计。过滤器拒绝成员时,归档可能已经解出部分文件;成功路径应在全部解包完成后再把临时目录原子改名,失败路径删除临时目录,避免消费者读到半成品。
最后按业务需要选策略
| 场景 | 建议 | 原因 |
|---|---|---|
| 普通数据包 | filter="data" | 直接采用标准库的数据包边界 |
| 不需要任何链接 | data_filter() 加 issym()/islnk() | 把链接能力明确关闭 |
| 可信备份恢复 | 只在来源和权限都可控时评估 fully_trusted | 保留 tar 元数据的代价更高 |
| 旧 Python 运行时 | 优先升级,或使用独立审查过的解包层 | 旧版本没有同一套 filter API |
一句话总结:限制链接路径的入口是 extractall(filter=...),基础规则交给 data 过滤器,业务不需要链接时再返回 None 跳过软链接和硬链接;最后用临时目录、权限和资源配额补上标准库过滤器不负责的部分。
常见问题
filter="data" 会不会保证所有 tar 包都安全?
不会。它主要限制路径越界、危险链接和特殊文件,并收紧部分元数据;文件数量、展开总大小、业务内容和运行权限仍要由应用处理。
为什么不只判断成员名是否包含 ..?
因为绝对路径、规范化后的越界路径和链接目标是不同情况。字符串判断容易漏掉组合路径,也无法表达链接是否允许。
过滤器返回 None 会报错吗?
不会。对自定义 extraction filter 来说,返回 None 表示跳过当前成员;官方过滤器拒绝危险成员时通常会抛出 FilterError。
Python 3.11 如何复用这套写法?
3.11 没有 extraction filter 参数和同一套内置过滤器。应优先升级到支持该 API 的版本;如果必须兼容旧版本,要单独采用经过审查的解包层,并把版本差异写进部署约束。
Python EmailMessage 怎样同时发送纯文本和 HTML
- 上一篇
- Python EmailMessage 怎样同时发送纯文本和 HTML
- 下一篇
- Python sqlite3 怎样使用上下文管理事务
-
- 文章 · python教程 | 1小时前 |
- Python 3.14 升级后怎样检查扩展模块兼容
- 373浏览 收藏
-
- 文章 · python教程 | 1小时前 | 标准库 · uuid · Python教程 · Python 自定义字段 RFC 9562 uuid.uuid8 UUIDv8 uuid.uuid4
- Python uuid.uuid8 怎样生成带自定义字段的 UUID
- 152浏览 收藏
-
- 文章 · python教程 | 1小时前 | 标准库 · xml · Python教程 · Python xml 流式解析 ElementTree xml.etree.ElementTree iterparse
- Python xml.etree.ElementTree.iterparse 怎样流式读取大 XML
- 339浏览 收藏
-
- 文章 · python教程 | 1小时前 |
- Python json.loads 怎样处理重复键
- 424浏览 收藏
-
- 文章 · python教程 | 1小时前 | SQLite · 事务管理 · Python教程 · Python 事务 上下文管理器 sqlite3 autocommit isolation_level Connection
- Python sqlite3 怎样使用上下文管理事务
- 257浏览 收藏
-
- 文章 · python教程 | 1小时前 |
- Python EmailMessage 怎样同时发送纯文本和 HTML
- 177浏览 收藏
-
- 文章 · python教程 | 1小时前 |
- Python compression.zstd 怎样用 ZstdDict 压缩重复数据
- 184浏览 收藏
-
- 文章 · python教程 | 1小时前 | 位置参数 partial Python 3.14 functools.Placeholder partialmethod
- Python functools.Placeholder 怎样组合非首位参数
- 237浏览 收藏
-
- 文章 · python教程 | 1小时前 |
- Python concurrent.interpreters 怎样创建解释器实例
- 480浏览 收藏
-
- 文章 · python教程 | 1小时前 |
- Python typing.ReadOnly 怎样标记 TypedDict 中不可修改字段
- 218浏览 收藏
-
- 文章 · python教程 | 1小时前 | 格式化 · Template Python 3.14 t-string string.templatelib template strings Interpolation
- Python 3.14 template strings 怎样延迟格式化
- 418浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 857次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 862次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 938次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 919次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 747次使用
-
- Go archive/tar 怎么保留目录结构解包到指定目录
- 2026-09-07 136浏览
-
- Go archive/tar 解包时为什么会出现 ErrInsecurePath
- 2026-09-26 142浏览
-
- Diffusers ControlNet 条件图尺寸匹配的处理
- 2026-10-02 314浏览
-
- Python 3.11.16 tarfile 修复如何影响解包服务
- 2026-09-11 242浏览
-
- Python 3.15 lazy imports 对 CLI 启动优化有什么启发
- 2026-10-13 404浏览
