存档解压缩期间的任意文件访问(“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
如果存档中的文件名未正确验证,则从恶意 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);
}
});
参考资料¶
Snyk:Zip Slip 漏洞。
OWASP:路径遍历。
常见弱点枚举:CWE-22。