资讯动态

Backstage TechDocs 路径穿越防护:拒绝解析到源目录之外的符号链接

发布时间:2026/9/10 3:40:20 来源:尧图企业网站定制
Backstage TechDocs 路径穿越防护拒绝解析到源目录之外的符号链接【免费下载链接】backstageBackstage is an open framework for building developer portals项目地址: https://gitcode.com/GitHub_Trending/ba/backstage导读本文围绕 Backstage 仓库中backstage/plugin-techdocs-node的一个安全补丁展开TechDocs 文档生成器现在会拒绝包含「解析到源目录之外」的符号链接symlink的源码树。文章将带你梳理该补丁引入的validateInputDirectory校验逻辑、其底层使用的isChildPath实现原理、与既有docs_dir校验的关系以及配套测试覆盖的攻击场景帮助你理解 Backstage 是如何在文档生成链路上防范路径穿越Path Traversal类任意文件读取攻击的。补丁背景一次针对符号链接的路径穿越加固在 .changeset/quiet-cats-protect.md 中记录了如下变更Updated TechDocs generation to reject source trees containing symlinks that resolve outside the source directory. TechDocs 文档生成现在会拒绝包含「解析到源目录之外」的符号链接的源码树。这是一条针对backstage/plugin-techdocs-node包的patch级变更即向后兼容的缺陷修复。它解决的问题是当 Backstage 从源码仓库例如 GitHub拉取实体目录并通过 TechDocs 生成静态文档站点时如果该目录树中存在指向源目录之外的符号链接例如指向宿主机的/etc/passwdMkDocs 及其扩展在构建过程中就有可能读取并泄露这些任意文件构成路径穿越类安全漏洞。在 CHANGELOG.md 中也同步记录了该提交commite58d265确认这一校验已进入techdocs-node的发布历史。校验的入口生成流程中的强制检查validateInputDirectory定义于 helpers.ts并在文档生成的主流程中被强制调用。在 techdocs.ts 中可以看到调用点// Validate that no symlinks in the input directory point outside it. MkDocs // extensions can access files throughout the input directory, not just docs_dir. await validateInputDirectory(inputDir);该调用发生在生成器Generator构建文档站点的准备阶段generate流程中紧随validateMkdocsYaml对mkdocs.yml中docs_dir的校验之后。也就是说Backstage 在真正调用mkdocs build之前会先对源目录做一次全局的符号链接安全检查。校验的实现全目录递归扫描 realpath 归一化validateInputDirectory的核心实现如下helpers.tsexport const validateInputDirectory async ( inputDir: string, ): Promisevoid { const entries await fs.readdir(inputDir, { recursive: true, withFileTypes: true, }); for (const entry of entries) { if (!entry.isSymbolicLink()) { continue; } const entryPath path.join(entry.parentPath, entry.name); // isChildPath resolves both paths through realpath, so this also catches // relative, chained and dangling links if (!isChildPath(inputDir, entryPath)) { throw new NotAllowedError( Path ${entryPath} is not allowed to refer to a location outside ${inputDir}, ); } } };实现要点如下递归枚举使用fs.readdir(inputDir, { recursive: true, withFileTypes: true })一次性递归遍历整个源目录树收集所有目录项Dirent而不是只扫描docs_dir。只处理符号链接通过entry.isSymbolicLink()过滤只有符号链接才进入检查普通文件与目录直接跳过因此对绝大多数正常源码树的性能开销极小。路径判定对每个符号链接的完整路径调用isChildPath(inputDir, entryPath)判断其真实指向是否仍位于源目录之内若不在则抛出NotAllowedError来自 backstage/errors错误信息形如Path entryPath is not allowed to refer to a location outside inputDir。为什么检查的是整个输入目录而不是 docs_dir函数注释给出了明确的设计动机helpers.tsThe whole input directory is checked rather than only the docs directory, because MkDocs extensions can read files from anywhere in the input directory.即MkDocs 的扩展如mkdocs-macros、snippets 等可以从源目录的任何位置读取文件而不仅仅局限于docs_dir。因此若只校验docs目录攻击者完全可以利用源目录根部的符号链接配合 snippets 语法--8-- leak_link泄露文件测试用例 helpers.test.ts 正是模拟了这种「符号链接位于源目录根部、但可通过 docs 内的 snippet 引用」的场景。底层原理isChildPath 如何识别符号链接的真实指向isChildPath是判断路径是否位于基准目录之内的公共工具由backstage/cli-common提供并通过 packages/backend-plugin-api/src/paths.ts 重新导出使后端包无需直接依赖cli-common。其实现位于 packages/cli-common/src/isChildPath.tsexport function isChildPath(base: string, path: string): boolean { const resolvedBase resolveRealPath(base); const resolvedPath resolveRealPath(path); const relativePath relative(resolvedBase, resolvedPath); if (relativePath ) { // The same directory return true; } const outsideBase relativePath.startsWith(..); // not outside base const differentDrive isAbsolute(relativePath); // on Windows, this means dir is on a different drive from base. return !outsideBase !differentDrive; }关键点在于resolveRealPathisChildPath.ts它负责把路径解析为「真实路径」常规情况直接使用fs.realpathSync解析自动跟随所有符号链接若路径不存在ENOENT则处理悬空符号链接递归地沿符号链接链向上解析目标例如link1 - link2 - /outside这样的链接链也能被识破若目标路径本身不存在则向上逐级找到最近存在的父目录并解析再把不存在的部分拼接回去。正是因为有realpath归一化isChildPath(inputDir, entryPath)才能判断符号链接的最终真实指向是否落在源目录之外而不仅仅是比较链接文件本身的字符串路径。这也解释了代码注释中的断言相对链接、链式链接、悬空链接统统会被捕获。与 resolveSafeChildPath 的配合同样的isChildPath还被用于 resolveSafeChildPath用于「从用户输入解析路径时保证结果位于基准目录内」的安全场景。可以看到isChildPath是整个 Backstage 后端路径安全体系的基础组件而本次 TechDocs 的加固正是复用了这套成熟工具而不是重新发明轮子。与既有 docs_dir 校验的层次关系本次补丁并非 TechDocs 的第一道路径安全防线。在此之前生成流程中已有对mkdocs.yml中docs_dir的校验见 validateMkdocsYamlif ( parsedMkdocsYml.docs_dir !isChildPath(inputDir, resolvePath(inputDir, parsedMkdocsYml.docs_dir)) ) { throw new Error( docs_dir configuration value in mkdocs cant be an absolute directory or start with ../ for security reasons. Use relative paths instead which are resolved relative to your mkdocs.yml file location., ); }这条旧校验防止的是docs_dir被配置为绝对路径或以../开头从而把mkdocs build的工作目录引向源目录之外。但它只约束了配置文件声明的目录无法约束文件系统中实际存在的符号链接——攻击者可以在不修改mkdocs.yml的前提下直接用符号链接把目录内容「嫁接」到外部。因此本次补丁与旧校验形成互补的纵深防御防线校验对象防护目标对应代码validateMkdocsYamlmkdocs.yml中的docs_dir配置防止构建目录被配置指向源目录外helpers.tsvalidateInputDirectory源目录树中的所有符号链接防止链接的真实指向逃逸出源目录helpers.ts两道校验在 techdocs.ts 中依次执行先校验配置再扫描目录树。测试覆盖从正常目录到恶意链接的攻击矩阵validateInputDirectory的单元测试位于 helpers.test.ts使用createMockDirectory构造临时目录树覆盖了完整的「放行/拒绝」矩阵放行合法场景无符号链接的正常源目录L1692-L1703指向目录内部文件的符号链接L1705-L1722指向目录内部目录的目录符号链接L1825-L1844指向源目录自身、构成环的符号链接L1846-L1859——因为其真实路径仍等于源目录isChildPath判定为true。拒绝恶意场景指向源目录外部文件的链接L1724-L1748如指向另一目录中的tmp/secret指向敏感系统文件的链接L1750-L1763测试用例直接使用/etc/passwd位于源目录根部、绕过 docs 目录的链接L1765-L1779配合 docs 内--8-- leak_linksnippet 语法演示泄露路径嵌套目录中的外部链接L1781-L1797指向外部的目录符号链接L1799-L1823。从测试矩阵可以看出该校验在「拒绝越界」的同时刻意保留了「目录内合法复用」的能力内部链接、内部目录链接、甚至自环链接均放行避免误伤合法的符号链接用法例如将共享的图片资源目录链接进 docs。受影响包与升级建议受影响包backstage/plugin-techdocs-node变更类型patch缺陷修复向后兼容变更内容TechDocs 生成器在构建前拒绝包含解析到源目录之外符号链接的源码树对于自托管 Backstage 的用户只需将backstage/plugin-techdocs-node升级到包含该补丁的版本即可获得防护。该修复对正常文档项目无感知只要你的源目录中的符号链接全部指向目录内部例如在仓库内复用资源生成流程照常工作而一旦源码树中出现指向外部的链接无论是相对链接、链式链接还是悬空链接构建会在mkdocs build之前被NotAllowedError中止并给出明确的错误信息指出违规路径便于快速定位问题。小结本文围绕 .changeset/quiet-cats-protect.md 中记录的符号链接校验补丁拆解了 TechDocs 路径穿越防护的完整链路触发点文档生成流程在mkdocs build前强制调用validateInputDirectorytechdocs.ts扫描策略递归遍历整个源目录树仅对符号链接条目做检查兼顾安全与性能helpers.ts判定核心复用isChildPath通过realpath归一化捕获相对、链式、悬空三类越界链接isChildPath.ts纵深防御与既有docs_dir配置校验互补覆盖「配置逃逸」与「文件系统逃逸」两种路径helpers.ts测试保障9 组单元测试完整覆盖合法放行与恶意拒绝场景helpers.test.ts。该补丁是 Backstage 在文档生成链路上的一次小而关键的加固体现了其在处理不可信源码树如外部仓库导入的实体目录时的安全基线宁可拒绝构建也不让任意文件读取的风险进入生成链路。【免费下载链接】backstageBackstage is an open framework for building developer portals项目地址: https://gitcode.com/GitHub_Trending/ba/backstage创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价