Golang 防止路径遍历漏洞

2023-03-16 15:34:28 浏览数 (2)

文章目录

  • 1.什么是路径遍历漏洞
  • 2.发生的业务场景
  • 3.路径遍历漏洞的危害
  • 4.Golang 避免路径遍历漏洞
    • filepath.Clean()
    • filepath.Join()
  • 5.小结
  • 参考文献

1.什么是路径遍历漏洞

路径遍历漏洞,也被称为目录遍历漏洞,是一种常见的安全漏洞类型,攻击者可以通过该漏洞访问或修改应用程序之外的目录或文件。

这种漏洞通常由于应用程序在接受用户输入时没有正确过滤或验证用户提供的文件路径导致。攻击者可以通过构造特定的输入,使得应用程序执行意外的操作,例如读取敏感文件、修改应用程序之外的文件或删除文件等。

假设有人向 IAP GCS 代理发送以下请求:

代码语言:javascript复制
curl https://gcs-iap-proxy.company.com/../another_bucket/super_important_file.txt

如果不对用于输入的路径进行过滤,那么上面的请求路径将被路由到其他桶,导致重要数据泄露。

2.发生的业务场景

路径遍历攻击是一种常见的Web安全漏洞,攻击者利用该漏洞可以访问应用程序的文件系统,执行任意文件操作。

  • 比如文件上传功能:当应用程序允许用户上传文件时,攻击者可以通过修改文件名或文件路径的方式,将文件保存在系统中的其他目录中,甚至可以上传恶意文件,导致系统被攻击。
  • 比如路径导航:应用程序中的一些页面可能允许用户访问特定文件或目录,攻击者可以通过修改URL,跳转到系统中的其他目录中,访问敏感文件或执行操作。
  • 比如日志文件:应用程序的日志文件可能包含敏感信息,攻击者可以通过利用路径遍历漏洞,访问和下载日志文件,获取敏感信息。
  • 比如 Web 服务器配置文件:攻击者可以通过访问Web服务器的配置文件,修改服务器的配置,包括重定向网站的URL或执行其他恶意操作。

为了防止路径遍历攻击,应用程序可以采取以下措施:

  • 对用户上传的文件进行检查和验证,限制上传文件的类型和大小,以及检查文件名和路径,确保它们不包含恶意代码。
  • 使用白名单来限制用户可以访问的文件和目录,避免让用户访问系统中的敏感文件和目录。
  • 对应用程序的日志文件进行保护,确保日志文件只能被授权人员访问。
  • 对 Web 服务器的配置文件进行保护,并限制对配置文件的访问,只允许授权人员访问。

3.路径遍历漏洞的危害

路径遍历漏洞可能导致以下危害:

  • 攻击者可以访问应用程序之外的敏感文件,例如密码文件、证书文件、配置文件等。
  • 攻击者可以在应用程序之外创建、修改或删除文件,例如在 Web 根目录下创建恶意文件、删除应用程序文件等。
  • 攻击者可以绕过应用程序的安全控制,例如上传恶意文件、执行远程命令等。

这些攻击可能导致数据泄露、数据破坏、服务拒绝等严重后果,严重影响应用程序的可用性、完整性和机密性。

4.Golang 避免路径遍历漏洞

在 Golang 中,可以使用 path/filepath 包中的 Clean() 或 Join() 函数来避免路径遍历漏洞。

filepath.Clean()

Clean() 函数可以清除路径中的冗余信息,例如 . 和 …,从而避免路径遍历攻击。

从文档(和源代码注释)中可以看出 filepath.Clean() 做了如下几件事情。

  • 将多个分隔符替换为单个。
  • 消除每个 . 路径名元素(当前目录)。
  • 消除每个内部 … 路径名元素(父目录)。
  • 消除以根路径开头的 … 元素:即,假设分隔符为"/“,将路径开头的”/…“替换为”/"。

例如:

代码语言:javascript复制
package main

import (
	"fmt"
	"path/filepath"
)

func main() {
	strs := []string{
		".",
		"..",
		"/foo/./../bar",
		"foo/../bar",
		"..foo/./../bar",
		"foo/../../../bar/baz",
	}
	for _, s := range strs {
		fmt.Println(filepath.Clean(s))
	}
}

运行输出:

代码语言:javascript复制
.
..
/bar
bar
bar
../../bar/baz

路径中的 . 和内部的 … 均被清除了。

使用 filepath.Clean() 还有一点需要注意的是,如果以 …/ 字符串开始时没有前导分隔符,则该字符串将保持不变。

代码语言:javascript复制
fmt.Println(filepath.Clean("../../foo"))

输出:

代码语言:javascript复制
../../foo

filepath.Join()

Join 将任意数量的路径元素连接到一个路径中,用操作系统特定的分隔符将它们分开。 空元素将被忽略。 结果是干净的。 但是,如果参数列表为空或其所有元素都为空,则 Join 返回空字符串。 在 Windows 上,如果第一个非空元素是 UNC(Universal Naming Convention)路径,则结果只会是 UNC 路径。

如果需要对路径清理,建议将路径分隔与待清洗的路径使用 Join 拼接起来,这样非法的路径元素会自动被清除。然后再去除根目录便得到合法的路径。

代码语言:javascript复制
package main

import (
	"fmt"
	"path/filepath"
	"strings"
)

func main() {
	strs := []string{
		".",
		"..",
		"/foo/./../bar",
		"foo/../bar",
		"..foo/./../bar",
		"foo/../../../bar/baz",
		"../../foo",
	}
	for _, s := range strs {
		fmt.Println(strings.TrimPrefix(filepath.Join(string(filepath.Separator), s), string(filepath.Separator)))
	}
}

运行输出:

代码语言:javascript复制
bar
bar
bar
bar/baz
foo

“.” 和 “…” 和路径分隔符拼接后的结果均是 “/”,所以去除分隔符后变成空串。

另外可以看到,以 …/ 开头的路径也被成功地清理了。

5.小结

路径遍历漏洞一种常见的 Web 安全漏洞,在很多业务场景都有可能发生。

但路径遍历漏洞不仅存在于 Web 应用程序,比如解压一个文件时,如果没有对文件名称进行清理,也会被坏人利用漏洞发起路径遍历攻击,将恶意文件解压至指定目录或覆盖原有的文件。

所以在处理用户输入的路径时,要多加小心。


参考文献

OpenAI ChatGPT Preventing path traversal in Golang - Matous Dzivjak github.com/golang/go:proposal: path/filepath: addition of SecureJoin helper

0 人点赞