首页 > 解决方案 > 检查文件是否位于基本目录中的最安全方法是什么?

问题描述

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

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

结果将被提供给外部函数,例如os.Createsqlite3.Open并且任何未能识别出基本路径被留下将是安全违规。

标签: filevalidationgopath

解决方案


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

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

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

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

  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

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


推荐阅读