路径安全

2026/07/27

写web经常会遇到路径拼接

最简单的实现就是

root:="/home/xxx/files"
target:="/a/b"
full:=root+target

直接拼接两个字符串,简洁明了 但是并不意味着安全:

1.路径穿越

“/home/xxx/files”+"../a/b",这样就访问到别的目录了

解决方案:拼接后clean,变成"/home/xxx/a/b",再和"/home/xxx/files"做前缀判断

比较直觉的写法是

strings.HasPrefix(full, root)

但这也是不对的,可以通过拼凑前缀来越过:

root  := "/data/disk"
target := "../disk2/secret"
full  := root + target // /data/disk2/secret
HasPrefix(full, root) == true

所以还要做相对化

rel, err := filepath.Rel(root, full)
if err != nil || strings.HasPrefix(rel, "..") {
	return "", fmt.Errorf("storage/local: location %s illegal %v", loc.Path, err)
}

2.不合法路径

当target为 “”/".“时,会发生什么?

target=”" full="/data/disk" rel="." pass=true target="." full="/data/disk" rel="." pass=true

要对target做提前判断

if loc.Path == "" || loc.Path == "." {
    return "", fmt.Errorf("storage/local: empty location path")
}

null 字节(\x00):部分系统会截断文件名; 换行/控制字符:污染日志、出问题的 shell 拼接。

也是同理要进行拦截

if strings.ContainsAny(loc.Path, "\x00") {
    return "", fmt.Errorf("storage/local: illegal characters in path")
}
  1. 符号链接:当前是纯字符串校验,要知道它的边界

Abs/Clean/Rel 全是字符串操作,不解析 symlink。威胁场景:

对"应用层抗 bit rot"的 NAS,一般两个做法:

我建议先走第一种 + 文档声明,等你确认部署形态(双盘位 NAS,root 是固定挂载点)再决定要不要 EvalSymlinks