在Golang中实现类似NPM的自动运行govulncheck功能(适用于go get/install/mod命令)

在Golang中实现类似NPM的自动运行govulncheck功能(适用于go get/install/mod命令) 与 NPM 不同,Go 语言中的基础软件成分分析(SCA)是可选的。这导致其生态系统落后于其他编程语言数十年。

请在默认情况下执行 go getgo installgo mod 命令时触发 govulncheck。

7 回复

任何使用Go语言的人都应该能够自动获得这些安全报告,开箱即用。选择加入会损害生态系统。

更多关于在Golang中实现类似NPM的自动运行govulncheck功能(适用于go get/install/mod命令)的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


真正需要了解漏洞的人肯定知道如何触发 vulncheck。而且,既然你实际上可以直接阅读你所使用包的 Go 代码,就有可能亲眼看到第三方库内部发生了什么。

我并非要求Go拒绝启动不安全的应用程序。或者编译不安全的组件。或者引入不安全的依赖。或者缓存不安全的模块。或者以非零状态退出。

我要求的是让用户意识到潜在的漏洞,以便他们能获得充分的信息。然后他们可以根据自己的需求做出应对。

Go 模块的下游用户甚至意识不到这些漏洞的存在。这就是默认安全状况的糟糕程度。作为对比,.NET 甚至开箱即用地显示了 CVE 信息。

之所以称之为生态系统,是因为它由众多协同工作的组件构成。你可以自行决定要做什么、在哪里做以及如何去做。安装工具的默认行为是将第三方包安装到项目中以便使用,而不是进行代码检查、扫描或其他操作。你随时可以编写脚本并为命令行执行创建别名,以运行你所需的一切操作。

请问,应该由谁来触发这些检查?如果是关于工具的问题,你可以在Go的GitHub上提交一个请求。

Go的生态系统远超大多数编程语言。但正如这门语言的设计哲学所体现的那样,你已经拥有了构建所需功能的所有基础模块。有很多人并不需要触发这些检查,或者任何其他可用的工具。因此,没有必要将它们添加到标准流程中。

在Go中实现类似NPM的自动安全扫描,可以通过创建自定义命令包装器或使用Go工具链钩子来实现。以下是几种实现方案:

方案一:创建自定义命令包装器(推荐)

// go-secure.go
package main

import (
    "fmt"
    "os"
    "os/exec"
    "strings"
)

func main() {
    if len(os.Args) < 2 {
        fmt.Println("Usage: go-secure [get|install|mod] ...")
        os.Exit(1)
    }

    command := os.Args[1]
    args := os.Args[2:]

    // 执行原始go命令
    cmd := exec.Command("go", append([]string{command}, args...)...)
    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr
    cmd.Stdin = os.Stdin
    
    if err := cmd.Run(); err != nil {
        os.Exit(1)
    }

    // 执行安全扫描
    if shouldRunVulnCheck(command, args) {
        runGovulncheck()
    }
}

func shouldRunVulnCheck(command string, args []string) bool {
    // 只在特定命令后运行扫描
    switch command {
    case "get", "install", "mod":
        return true
    default:
        return false
    }
}

func runGovulncheck() {
    fmt.Println("\n=== 运行安全漏洞扫描 ===")
    
    cmd := exec.Command("govulncheck", "./...")
    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr
    
    if err := cmd.Run(); err != nil {
        fmt.Printf("安全扫描完成(退出码: %v)\n", err)
    }
}

方案二:使用Git钩子或Makefile

# Makefile
.PHONY: get install mod tidy

get:
    go get $(ARGS)
    govulncheck ./...

install:
    go install $(ARGS)
    govulncheck ./...

mod:
    go mod $(ARGS)
    ifneq (,$(findstring tidy,$(ARGS)))
        govulncheck ./...
    endif

tidy:
    go mod tidy
    govulncheck ./...

方案三:集成到go.mod的replace指令

// go.mod
module your-project

go 1.21

replace github.com/your-org/go-wrapper => ../go-wrapper

require github.com/your-org/go-wrapper v0.0.0
// go-wrapper包中的实现
package gowrapper

import (
    "golang.org/x/tools/go/packages"
    "golang.org/x/vuln/client"
    "golang.org/x/vuln/vulncheck"
)

type SecureModule struct {
    client.Client
}

func (s *SecureModule) Load(pattern string) ([]*packages.Package, error) {
    pkgs, err := packages.Load(&packages.Config{}, pattern)
    if err != nil {
        return nil, err
    }
    
    // 自动运行漏洞检查
    go s.runVulnerabilityCheck(pkgs)
    
    return pkgs, nil
}

func (s *SecureModule) runVulnerabilityCheck(pkgs []*packages.Package) {
    cfg := &vulncheck.Config{Client: s.Client}
    result, err := vulncheck.Source(context.Background(), pkgs, cfg)
    if err != nil {
        return
    }
    
    // 输出漏洞报告
    vulncheck.PrintResults(result, vulncheck.Text)
}

方案四:使用go generate指令

// 在main.go或其他文件中添加
//go:generate go run scripts/vulncheck.go

// scripts/vulncheck.go
package main

import (
    "os"
    "os/exec"
)

func main() {
    // 检查是否在CI环境或特定条件下运行
    if os.Getenv("RUN_VULNCHECK") != "false" {
        cmd := exec.Command("govulncheck", "./...")
        cmd.Stdout = os.Stdout
        cmd.Stderr = os.Stderr
        cmd.Run()
    }
}

安装和使用

# 安装包装器
go build -o /usr/local/bin/go-secure go-secure.go

# 创建别名(在.bashrc或.zshrc中)
alias go="go-secure"

# 使用示例
go get github.com/some/package
# 自动运行: govulncheck ./...

go install golang.org/x/tools/gopls@latest
# 自动运行: govulncheck ./...

这个实现会在执行go getgo installgo mod命令后自动触发govulncheck扫描,提供类似NPM的自动安全检查功能。

回到顶部