如何修复Semgrep扫描提示的文件路径用户可控变量验证问题?
修复Semgrep检测到的非字面量FS文件名安全问题
核心问题分析
你之前的修复无效,主要原因:
- 仅移除开头的
../,无法处理文件名中间嵌入的路径遍历字符(比如abc/../malicious.zip) - 使用
realpath时错误地再次拼接容器路径,导致路径逻辑混乱 - 未验证最终路径是否严格限定在目标容器目录内
有效修复方案
要彻底解决路径遍历风险,需完成三点:
- 强制提取纯文件名,剥离所有路径组件
- 生成安全的绝对路径
- 验证最终路径归属,确保它严格在目标容器目录内
代码示例
import * as path from 'path'; import * as fspromise from 'fs/promises'; public async artFacts(artifact: Artfact): Promise<Artfact> { const rawFileName = artifact.getName(); // 1. 仅保留纯文件名,自动剥离所有路径字符(/、\、../等) const safeFileName = path.basename(rawFileName); // 2. 拼接容器路径与安全文件名,生成绝对路径 const targetPath = path.resolve(envConfig.artfacts_container_path, safeFileName); // 3. 验证目标路径是否属于容器目录范围 const containerAbsolutePath = path.resolve(envConfig.artfacts_container_path); if (!targetPath.startsWith(containerAbsolutePath + path.sep)) { throw new Error('Invalid file name: Path traversal detected'); } // 4. 安全读取文件 const fileContent = await fspromise.readFile(targetPath); // 后续业务逻辑 // ... return artifact; }
关键细节说明
path.basename():自动忽略所有路径前缀,比如输入../abc/zyx-anony-detect-v1.zip,会直接返回zyx-anony-detect-v1.zippath.resolve():生成绝对路径,避免相对路径的歧义- 路径归属验证:即使出现极端构造(比如safeFileName为
../etc/passwd),path.resolve会生成/etc/passwd,此时startsWith检查会失败,直接阻断操作
替代方案(正则严格过滤)
如果需要自定义允许的字符,可通过正则过滤掉所有非法路径字符:
// 仅允许字母、数字、-、_、.,禁止所有路径分隔符和遍历字符 const safeFileName = rawFileName.replace(/[^\w\-.]/g, ''); // 后续步骤同上
内容的提问来源于stack exchange,提问作者Swarup
相关产品推荐
相关产品推荐

