必须绕开shell,直接使用exec.command传参;用户输入不可拼入sh -c等shell调用,无论是否转义;参数需白名单校验与路径清理,安全关键在于避免shell解析而非净化字符串。

直接拼接用户输入进 sh -c 或类似 shell 调用,没有“净化”能救你——必须绕开 shell。所谓“净化参数字符串”,本质是误判风险点:真正危险的不是字符本身,而是执行路径是否经过 shell 解析。
os/exec.Command("sh", "-c", ...) 一律禁止
任何把用户输入塞进 sh -c、bash -c、dash -c、python -c 的写法,无论加不加引号、转义多少层,都等于把钥匙交给攻击者。Go 不会帮你解析引号嵌套或反斜杠逃逸,shell 才会。
-
exec.Command("sh", "-c", "ls "+ userInput)→ ❌ 危险,userInput是"*.log; rm -rf /"就完蛋 -
exec.Command("sh", "-c", "ls '$1'", "dummy", userInput)→ ❌ 依然危险,$1在 shell 层仍会被展开、分词、执行 - 查
exec.LookPath("sh") == nil并不能说明安全——攻击者可能用/bin/dash或/usr/bin/python3绕过检测
用 exec.Command 直接调用程序,但参数仍需校验
os/exec.Command 本身不走 shell,参数以切片传入,这是安全基线。但操作系统在 execve 前可能对含通配符(*、?)、空格或路径穿越(../)的参数做 glob 展开或路径解析,Go 不干预这个过程。
-
exec.Command("ls", "/tmp/*.log")→ 可能展开成多个文件,若/tmp/下有恶意命名文件(如$(rm -rf /).log),某些 shell wrapper 环境下仍可能触发命令执行 -
exec.Command("cat", "../etc/passwd")→ 若未做路径清理,直接读取敏感文件 - 校验要点:
filepath.Clean(input)后检查是否仍在白名单根目录下(如strings.HasPrefix(cleaned, "/var/data/")) - 对命令名也应白名单校验(如只允许
"tar"、"grep"、"sha256sum"),避免用户控制二进制路径
动态字段(如 ORDER BY、LIMIT)无法参数化时怎么处理
SQL 中 ORDER BY、LIMIT、表名、列名等语法位置不支持参数绑定,必须拼接。此时“净化”不是过滤字符,而是严格白名单匹配。
- 拒绝所有非字母数字和下划线的字符?不够——
title ASC; DROP TABLE users仍是合法排序方向 - 正确做法:预定义可接受值,例如
map[string]bool{"title": true, "created_at": true, "id": true},再检查输入是否在其中 - 排序方向同理:
if dir != "ASC" && dir != "DESC" { return errors.New("invalid order direction") } - 不要试图用正则“删掉危险字符”,那只会漏掉新型绕过(比如 Unicode 变体、零宽空格)
别信“转义函数”能防 shell 注入
不存在一个通用的 escapeShellArg() 函数能让你安全地拼接进 shell。不同 shell(bash/zsh/dash)、不同调用方式(sh -c vs system())、不同上下文(双引号内/单引号内/无引号)转义规则完全不同,且 Go 标准库不提供这种函数——因为根本不可靠。
- 第三方库如
shellquote只适用于已确定必须走 shell 的极少数场景(如日志审计重放),且仅限简单参数,不保命 - 若真要走 shell,请改用
exec.Command("sh", "-c", script, "_", arg1, arg2)形式,并确保script是硬编码模板,所有用户输入只作为$1、$2传入——但仍需校验arg1、arg2是否合规 - 最稳妥的方案永远是:不用 shell。用
exec.Command("find", "-name", pattern, "-exec", "cp", "{}", dest, ";")替代sh -c "find ... -exec ... {} \;"
真正的安全不在“怎么净化字符串”,而在“是否让字符串进入 shell”。一旦路径经过 shell,再严密的净化也像给炸药桶装滤网——关键在源头隔离。路径穿越、glob 展开、alias 包裹这些隐性行为,比显式的 ; 或 && 更容易被忽略。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











