Skip to content
KitploitKITPLOIT
工具博客
提交
工具博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
safetext — 用于安全生成 YAML 和 shell 的 Go 库,使用语法感知模板,通过针对可信数据的注解来检测并阻止注入攻击。 | Kitploit
工具/GitHubGitHub/google/safetext
防御工具脚本与自动化Web安全DevSecOps
GitHubgoogle/safetext

safetext

用于安全生成 YAML 和 shell 的 Go 库,使用语法感知模板,通过针对可信数据的注解来检测并阻止注入攻击。

查看仓库
15094个月前Kitploit 审核通过

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

safetext

这不是 Google 官方支持的产品。

这些库采用 safe-by-construction(安全构造)方法生成 YAML 等格式,用来替代像 text/template 和 sprintf 这样不感知语法、易受注入漏洞影响的库。

示例用例

由于 text/template 不感知它生成格式的语法,因此它无法提供任何针对注入漏洞的防护。

请考虑下面这个使用 text/template 生成 YAML 的 produceConfig 函数:

root@kitploit:~
package main

import (
        "bytes"
        "fmt"
        "text/template"
)

func produceConfig(params any) (error, string) {
        tmpl, _ := template.New("test").Parse("{ hello: {{ .addressee }} }")

        var buf bytes.Buffer
        err := tmpl.Execute(&buf, params)
        if err != nil {
                return err, ""
        }

        return nil, buf.String()
}

func main() {
        goodReplacements := map[string]interface{}{
                "addressee": "safe",
        }

        err, config := produceConfig(goodReplacements)

        if err == nil {
                fmt.Println(config)
        } else {
                fmt.Printf("Error: %v\n", err)
        }

        badReplacements := map[string]interface{}{
                "addressee": "world, oops: true",
        }

        err, config = produceConfig(badReplacements)

        if err == nil {
                fmt.Println(config)
        } else {
                fmt.Printf("Error: %v\n", err)
        }
}

该程序演示了恶意 addressee 输入如何在模板执行结果中注入新的 YAML 键。

使用 text/template 时,发生这种情况不会遇到任何错误,程序输出将是:

root@kitploit:~
{ hello: safe }
{ hello: world, oops: true }

如果从 text/template 换成 safetext/yamltemplate,这种注入就会被阻止,输出将变为:

root@kitploit:~
{ hello: safe }
Error: YAML Injection Detected

text/template 替换说明

在访问输入数据字段时,会自动应用注入检测。

  • 也可以在任何函数调用的结果上手动启用:

    root@kitploit:~
    {{ RetrieveUntrustedData | ApplyInjectionDetection }}
    
  • 可以通过应用 StructuralData 注解,在特定字段上禁用注入逻辑:

    root@kitploit:~
    {{ (StructuralData .x) }}
    
  • 在将输入传递给某个函数且该输入不应被修改时(例如执行某种查找),也需要使用 StructuralData 注解:

    root@kitploit:~
    name: {{ readFile (StructuralData .pathToName) | ApplyInjectionDetection }}
    
  • 建议充分利用 text/template 的功能(如条件表达式、range 循环等),在可能的情况下避免使用 StructuralData 注解。例如,不要这样写:

    root@kitploit:~
    properties:
        {{ (StructuralData .PropertiesYaml) }}
    

    请考虑这样写:

    root@kitploit:~
    properties:{{ range .Properties }}
        - {{ . }}{{ end }}
    

yamltemplate

yamltemplate 的意图是确保默认情况下,输入数据中的任何字符串都不会影响最终 YAML 的结构(只影响值)。

  • 例如,下面的模板可以直接与 yamltemplate 兼容,同时自动防止来自 Name 输入的任何注入:

    root@kitploit:~
    name: {{.Name}}
    
  • 然而,任何预期会改变最终 YAML 结构的模板节点(例如插入任意 YAML 配置)都需要显式地标注为 StructuralData:

    root@kitploit:~
    config: {{ (StructuralData .Config) }}
    
  • 另一种需要 StructuralData 注解的情况是,你需要将完整的 map 包含到 YAML 结构中。单独使用 StructuralData 可能会让注入通过键(key)穿过,因此这里需要额外的验证层:

    root@kitploit:~
    labels:
    {{- range $key, $value := .Labels }}
        {{ (StructuralData $key | MapKey) }}: {{ $value }}
    {{- end }}
    

    对应的 Go 代码可能如下所示:

    root@kitploit:~
    func mapKeyFunc(data any) (string, error) {
        if v, ok := data.(string); ok {
            matched, err := regexp.MatchString(`^[a-zA-Z0-9/\-.]+$`, v)
            if err != nil {
                return "", err
            }
            if !matched {
                return "", fmt.Errorf("invalid characters in the key: %v", v)
            }
            return v, nil
        }
    
        return "", errors.New("invalid input")
    
    } ...
    
    tmp:= template.New("something")
    tmp.Funcs(map[string]any{"MapKey":mapKeyFunc})
    tmpl := template.Must(tmp.Parse(yamlTemplate))
    

yamltemplate 不支持的用例

带重复键的 YAML。重复键是非标准 YAML,此库不支持。请重构你的 YAML 模板以移除重复键。例如:

root@kitploit:~
- project:
   members: member-a
   members: member-b

改为:

root@kitploit:~
- project:
  members: member-b

shtemplate

shtemplate 旨在让你生成 shell 脚本,并保证在无需显式注解的情况下,输入数据字符串都无法注入新的命令或标志(flag)。

  • 例如,一个仅用于打印一个字符串的模板脚本,如果该字符串注入了新命令 `./evil`,则渲染将失败:

    root@kitploit:~
    echo "{{ .addressee }}"
    
  • 若要显式允许输入字符串包含并非来自模板字符串的新命令,可以使用 StructuralData 注解:

    root@kitploit:~
    {{ (StructuralData .commands) }}
    
  • 标志(以 - 开头的参数)在默认情况下也被禁止。例如,如果 Filename 是 --interactive,下面的模板将渲染失败:

    root@kitploit:~
    git add {{ .Filename }}
    
  • 若要显式允许作为命令参数传递的输入字符串是标志,可以使用 AllowFlags 注解:

    root@kitploit:~
    git add {{ (AllowFlags .FilenameOrGitAddFlag) }}
    
  • 默认情况下,从单个输入字符串生成多个参数也是被禁止的。这种构造应改用数组和 range 表达式来实现:

    root@kitploit:~
    ls {{ range .Paths }}{{.}} {{end}}
    

text/template 替换不支持的用例

  • 在模板系统之外进行转义逻辑。相反,你应该将转义逻辑注解到模板中(例如:.UntrustedField | escape)。

  • 部分格式。这些库设计用于生成完整文件。如果你生成片段然后再拼接,应该将此逻辑移到模板系统本身(使用 if 或 range 等构造)。

  • 带有副作用的函数。这些库通过多次执行模板来工作,因此如果你注册有副作用的函数,可能会导致意外行为(例如:id: {{ AllocateID }})。

shsprintf

shsprintf 旨在让你生成 shell 脚本,并保证无论潜在的转义是否正确,输入数据字符串都无法注入新的命令或标志。请参见下面的示例,该示例将返回错误 shsprintf.ErrShInjection,而不是带有注入命令的脚本:

root@kitploit:~
message := "`whoami`"
result, err := shsprintf.Sprintf("git commit -m %s", message)

与 fmt.Sprintf 相比,shsprintf.Sprintf 增加了一个错误返回值,但 API 在其他方面是相同的。在可接受 panic 的情况下,可以使用 shsprintf.MustSprintf。

shsprintf 附带一个建议使用的转义函数:

root@kitploit:~
message := "`whoami`"
result := shsprintf.MustSprintf("git commit -m %s", shsprintf.EscapeDefaultContext(message))

与 text/template 不同,这里没有特殊的注解。例如,如果需要传递多个参数,应通过修改格式字符串来实现:

root@kitploit:~
files := []any{ "file1", "file2", "file3" }
result, err := shsprintf.Sprintf("cat" + strings.Repeat(" %s", len(files)), files...)
下载工具
  • 你可以将 yamltemplate 与 shprintf 结合使用。请考虑下面的 cloud-init YAML 模板:

    root@kitploit:~
    ---
    write_files:
    - path: /etc/nginx/refresh.sh
      owner: root:root
      permissions: 0755  # Don't forget the 0 (you are probably using octal...)
      content: |
        #!/bin/bash
        set -euo pipefail
    
        {{ shprintf `curl %s > /tmp/something` .userInput }}
    

    使用 safetext/yamltemplate 渲染此模板时,shell 命令注入和 YAML 注入都将被阻止。

    为此,你需要在 Go 端进行如下设置:

    root@kitploit:~
    tmp:= addons.WithShsprintf(template.New("something"))
    tmpl := template.Must(tmp.Parse(yamlTemplate))