题目与适用场景
用户上传 ZIP 或 TAR.GZ,系统在后台解压后进行病毒扫描、文本提取或批量导入。攻击者可能上传压缩后很小、展开后极大的文件,构造递归嵌套归档,或利用条目路径写出目标目录。请说明上传边界、格式解析、资源预算、隔离、失败状态和清理策略。
题目重点是解压阶段的资源安全。假设文件最终会进入异步 worker,不能把“上传大小限制”当成全部防线;压缩比、条目数量和展开后的总量都必须进入设计。
面试官在考察什么
面试官会看你是否区分压缩前大小与解压后成本,是否把文件数、目录深度、嵌套层数、CPU、内存、磁盘和处理时限纳入预算。OWASP 明确建议在解压后计算大小并限制上传服务;OWASP WSTG 将 zip bomb 描述为通过耗尽磁盘或内存造成拒绝服务的归档。
高质量答案还应处理路径穿越、符号链接、重复文件名、错误大小声明、解析库漏洞和取消后的清理。隔离 worker、只写临时目录、原子发布和可观测性决定了系统能否把恶意输入限制在单个任务内。
30 秒回答框架
“我会把归档当作不可信输入。入口限制压缩包字节数、类型和请求速率;worker 在受限容器和临时目录中流式读取,先检查条目路径、符号链接、条目数、嵌套层数和解压后总字节预算。任何预算超限立即停止并清理。解压结果通过病毒扫描和内容类型检查后才原子发布,原始文件与任务状态保留审计信息但不直接公开。每个任务有 CPU、内存、磁盘和墙钟上限,并用指标观察拒绝率和清理是否完整。”
分步深入设计
第一步:建立输入和任务边界
入口限制压缩文件大小、单用户并发、总配额和请求频率。为任务分配 ID、租户、原始对象、解析格式和状态。原始对象存入不可执行的隔离存储,worker 只获得短时读取权限,不能把上传内容当作命令或配置加载。
第二步:识别格式并选择解析器
不要只看扩展名或 Content-Type;检查魔数与允许的格式集合。为 ZIP、TAR、GZIP 等格式选择维护中的库,并记录版本。解析器的条目大小字段可以帮助预检,但不能盲目信任未压缩大小;必须在实际读取时继续计数。加密归档、未知压缩方法和格式错误应进入拒绝或人工处理路径。
第三步:执行多维资源预算
至少定义压缩包字节数、展开字节数、文件数、单文件大小、目录深度、嵌套归档层数、CPU 时间、内存和墙钟预算。预算应按租户和任务类型配置,但每次都要有硬上限。压缩比只是告警信号,不能替代展开字节计数,因为不同数据和格式的压缩特征差异很大。
第四步:安全处理路径和文件系统对象
把条目名规范化后拒绝绝对路径、路径穿越和空字节。展开目标必须是每任务独立的临时目录,最终路径要验证仍位于该目录内。默认拒绝符号链接、硬链接和设备文件;不要跟随指向目录外的链接。重复文件名按明确策略拒绝,避免覆盖顺序造成安全绕过。
第五步:隔离解压和后续扫描
worker 运行在低权限容器或沙箱,使用只读根文件系统、临时磁盘配额、无网络或最小网络权限。解压和内容扫描分开设置预算,避免单个归档同时占满解压与扫描资源。扫描结果、提取文本和缩略图写入新的不可执行对象,未经策略允许不能直接提供给浏览器下载。
第六步:处理嵌套、递归和取消
如果业务不需要嵌套归档,直接拒绝其中包含归档的条目。需要支持时设置最大层数、总预算和每层路径检查,且递归任务共享同一个预算,而不是每层重新获得额度。超时、用户取消、worker 崩溃和租户删除都必须触发幂等清理,避免临时文件留下来继续占用磁盘。
第七步:状态机、发布和恢复
状态可分为 uploaded、inspecting、extracting、scanning、published、rejected 和 cleanup_failed。只有所有条目通过检查并完成扫描,任务才原子切换为 published。失败状态对用户给出安全原因和下一步;内部保留结构化拒绝码、预算消耗和库错误,方便审计与重试。重试不能跳过预算或重复发布。
第八步:测试与可观测性
测试高压缩比、嵌套归档、路径穿越、符号链接、重复名称、错误头部、超大条目、损坏 CRC、加密文件和中途取消。指标包括每任务展开字节、文件数、最大深度、CPU、拒绝原因、清理延迟、临时磁盘水位和 worker 重启率。用合成恶意样本验证上限在真实库版本中生效。
取舍、边界与信息增益
预扫描条目元数据成本低,却不能替代流式计数;完全流式处理更可靠,但可能在已经消耗部分资源后才发现超限。拒绝嵌套归档最安全,支持嵌套则能服务备份场景,但需要共享预算和递归深度。
将解压放在独立 worker 能降低主服务风险,却增加队列延迟和运维成本。把原始归档保留在隔离存储有助于重试与调查,但必须设置保留期限、访问控制和加密。任何“允许无限大小因为有异步队列”的说法都忽略了下游资源。
高质量示范回答
“我会把上传和解压分成两个信任边界。上传阶段限制字节数、并发和配额;异步 worker 在低权限、无网络的容器中使用维护中的解析库,只向任务临时目录写入。读取每个条目时同时累计展开字节和文件数,并限制单文件大小、目录深度、嵌套层数、CPU、内存、磁盘和墙钟。
条目路径规范化后拒绝绝对路径、穿越、符号链接、硬链接和设备文件。业务不需要嵌套时直接拒绝,需要时让所有层共享一个预算。扫描通过后才原子发布不可执行对象;超限、超时、取消和崩溃都走幂等清理。指标记录预算消耗、拒绝原因、清理延迟和临时磁盘水位,并用恶意归档持续回归测试。”
常见错误
- 只限制上传压缩包大小。 小文件也能在解压后耗尽磁盘或内存。
- 相信条目声明的未压缩大小。 解析器和格式边界可能让声明不完整或不可信。
- 把压缩比作为唯一规则。 高压缩比是信号,不是对所有格式的安全预算。
- 直接解压到共享目录。 路径穿越、覆盖和残留会影响其他租户。
- 允许符号链接或设备文件。 条目可能把写入引向目录外或特殊内核接口。
- 每层嵌套重新发放额度。 递归可以乘法放大资源消耗。
- 扫描通过就立即公开原始内容。 恶意脚本和错误内容类型仍可能攻击下载者。
- 取消后不清理临时目录。 长期残留会形成磁盘耗尽事件。
追问与参考答案
应该先扫描还是先解压?
需要读取归档才能扫描内部文件,但解压本身要受预算和隔离保护。先做格式与元数据检查,再在受限 worker 中流式解压,随后扫描每个结果。
压缩比超过多少就拒绝?
不能给出跨格式通用数字。压缩比可用于告警或提前拒绝,真正的硬门槛应是展开总字节、单文件、文件数和 CPU 等预算。
如何安全支持嵌套归档?
设置最大深度,让所有层共享总预算,每层重复路径和符号链接检查,并把递归处理限制在同一 worker 的墙钟和磁盘配额内。
解析库报告的条目大小可信吗?
它是预警信息而非授权依据。实际读取必须继续累计字节,处理数据描述符、Zip64、损坏头部和库已知限制,并锁定经过验证的库版本。
超限任务应该重试吗?
资源预算超限是确定性拒绝,不应盲目重试。只有暂时性 worker 故障才可重试,而且重试要重新创建隔离目录并保持同一预算与幂等状态。