【问题标题】:What is the safest way to check that a file resides within a base directory?检查文件是否位于基本目录中的最安全方法是什么?
【发布时间】:2020-03-24 11:01:06
【问题描述】:

在任何平台上验证给定文件路径是否位于基本路径中的 Go 中最安全和最安全的方法是什么?

路径最初以字符串形式提供并使用“/”作为分隔符,但它们是用户提供的,我需要假设 大量恶意输入。我应该执行哪种路径规范化以确保例如像“..”这样的序列被评估,所以我可以安全地检查基本路径?在各种文件系统和平台上需要注意哪些例外情况?在这方面,哪些 Go 库应该是安全的?

结果将被提供给os.Createsqlite3.Open 等外部函数,任何未能识别出基本路径已被留下的行为都将构成安全违规。

【问题讨论】:

  • 你尝试了什么?为什么 filepath.Clean 不足以满足您的目的。你如何定义“最安全”?

标签: file validation go path


【解决方案1】:

我相信您可以为此使用filepath.Rel(并检查它是否返回一个不以.. 开头的值)。

Rel 返回一个在词法上等价于 targpath 的相对路径 当使用中间分隔符连接到基本路径时。那是, join(basepath, Rel(basepath, targpath)) 等价于 targpath 本身。成功时,返回的路径将始终相对于 basepath,即使 basepath 和 targpath 不共享任何元素。一个错误是 如果 targpath 不能相对于 basepath 或者如果知道,则返回 当前的工作目录是计算它所必需的。相对 对结果调用 Clean。

filepath.Rel 还在其输入路径上调用filepath.Clean,解析任何.s 和..s。

Clean 返回与 path by pure等效的最短路径名 词法处理。它迭代地应用以下规则,直到 无法进行进一步处理:

  1. 将多个分隔符元素替换为一个。
  2. 消除每个 .路径名元素(当前目录)。
  3. 删除每个内部 .. 路径名元素(父目录)及其前面的非 .. 元素。
  4. 消除以根路径开头的 .. 元素:即,假设 Separator 为“/”,将路径开头的“/..”替换为“/”。

您也可以直接使用filepath.Clean 并在完成后检查前缀。以下是filepath.Clean 的一些示例输出:

ps := []string{
    "/a/../b",
    "/a/b/./c/../../d",
    "/b",
}
for _, p := range ps {
    fmt.Println(p, filepath.Clean(p))
}

打印:

/a/../b /b
/a/b/./c/../../d /a/d
/b /b

也就是说,路径操作不应该是您部署的唯一安全机制。如果您真的担心漏洞利用,请通过沙盒、创建虚拟文件系统/容器等进行深度防御。

【讨论】:

  • 例如,这不会防御路径中的符号链接。
  • @Adrian:正确,因此是答案的附录。根据安全需求,这不太可能是一个完全令人满意的解决方案。
猜你喜欢
  • 1970-01-01
  • 2015-02-21
  • 2020-01-17
  • 2011-01-31
  • 1970-01-01
  • 2023-03-16
  • 1970-01-01
  • 1970-01-01
  • 2010-09-18
相关资源
最近更新 更多