CodeQL 文档

存档解压缩期间的任意文件访问(“Zip Slip”)

ID: js/zipslip
Kind: path-problem
Security severity: 7.5
Severity: error
Precision: high
Tags:
   - security
   - external/cwe/cwe-022
Query suites:
   - javascript-code-scanning.qls
   - javascript-security-extended.qls
   - javascript-security-and-quality.qls

点击查看 CodeQL 仓库中的查询

如果存档中的文件名未正确验证,则从恶意 zip 文件或类似类型的存档中提取文件有目录遍历攻击的风险。存档路径。

Zip 存档包含代表存档中每个文件的存档条目。这些条目包括条目的文件路径,但这些文件路径不受限制,可能包含意外的特殊元素,例如目录遍历元素 (..)。如果这些文件路径用于创建文件系统路径,则文件操作可能会发生在意外的位置。这可能导致敏感信息被泄露或删除,或者攻击者能够通过修改意外文件来影响行为。

例如,如果一个 zip 文件包含一个文件条目 ..\sneaky-file,并且 zip 文件被解压缩到目录 c:\output,则天真地组合路径将导致输出文件路径为 c:\output\..\sneaky-file,这会导致文件被写入 c:\sneaky-file

建议

确保从 zip 存档条目构造的输出路径经过验证,以防止将文件写入意外位置。

从 zip 存档条目写入输出文件的推荐方法是检查路径中是否出现 ".."

示例

在此示例中,存档在未验证文件路径的情况下被解压缩。如果 archive.zip 包含相对路径(例如,如果它是由类似 zip archive.zip ../file.txt 的东西创建的),那么执行此代码可能会写入目标目录之外的位置。

const fs = require('fs');
const unzip = require('unzip');

fs.createReadStream('archive.zip')
  .pipe(unzip.Parse())
  .on('entry', entry => {
    const fileName = entry.path;
    // BAD: This could write any file on the filesystem.
    entry.pipe(fs.createWriteStream(fileName));
  });

为了修复此漏洞,我们需要检查路径中是否包含任何 ".." 元素。

const fs = require('fs');
const unzip = require('unzip');

fs.createReadStream('archive.zip')
  .pipe(unzip.Parse())
  .on('entry', entry => {
    const fileName = entry.path;
    // GOOD: ensures the path is safe to write to.
    if (fileName.indexOf('..') == -1) {
      entry.pipe(fs.createWriteStream(fileName));
    }
    else {
      console.log('skipping bad path', fileName);
    }
  });

参考资料

  • ©GitHub, Inc.
  • 条款
  • 隐私