Go 语言路径搜索安全问题

Go 语言里默认的 exec.Command 存在路径搜索安全问题,可以使用 import exec "golang.org/x/sys/execabs" 缓解。

0x01. PATH

在历史上,Unix 下 $PATH 默认值是 :/bin:/usr/bin,注意第一个冒号 :,这表示第一个路径是当前路径。也就是说,默认从当前路径开始搜索,这肯定会导致安全问题。所以,后面就把当前路径给去掉了,如果你在现代 Linux 中查看 $PATH 的值,会发现没有这个问题。

1
2
$ echo $PATH
/home/username/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin

而在 MS-DOS 和 Windows 上,对 CMDSearchPath 而言,当前目录 . 总是 %PATH% 的第一个搜索对象;PowerShell 则丢弃了这一隐式搜索行为。

0x02. exec.Command

在 Windows 上,如下代码会在当前目录搜索 gcc 并执行,这可能是一个安全问题。

1
2
3
4
import "os/exec"

cmd := exec.Command("gcc", "tmpfile.c")
cmd.Run()

缓解方案(如果当前目录存在 gcc,则直接返回错误):

1
2
3
4
import exec "golang.org/x/sys/execabs"

cmd := exec.Command("gcc", "tmpfile.c")
cmd.Run()

如果开发者确实需要运行当前目录下的 gcc,建议显示定义这个行为:

1
2
3
4
import "os/exec"

cmd := exec.Command("./gcc", "tmpfile.c")
cmd.Run()

0x03. Takeaway

在写代码时要拒绝 implicit 行为,如果你想要实现某一行为,请显示指明,就像 C++ 里的 explicit 关键字一样。

0x04. 参考文档

  1. https://go.dev/blog/path-security