Go环境变量

通过执行go help environment命令打印输出go命令识别的所有环境变量的信息列表。

go命令及其调用的工具会参考环境变量进行配置。如果环境变量未设置,go命令将使用合理的默认值。要查看环境变量<NAME>的值,请运行“go env<NAME>”。要更改默认设置的值,请运行“go env -w <NAME>=<VALUE>”。根据操作系统的报告,使用go env w命令更改的默认值将记录在每个用户的家目录中一个存储go环境变量的配置文件中,os.UserConfigDir函数的返回每个用户配置目录的路径。配置文件的路径可以通过设置环境变量GOENV来更改,go env GOENV命令可以打印输出当前设置的配置文件的路径,但无法通过go env -w来更改配置文件的路径。

有关go env命令可以通过go help env查看它的用法。

一、通用的环境变量

GO111MODULE:控制go命令是运行于模块模式还是GOPATH模式。值可以是off、on或auto。

GCCGO:为运行go build -compiler=gccgo设置的gccgo命令。

GOARCH:Go代码要编译到的CPU架构,例如amd64、386、arm、ppc64等。

GOBIN:运行go install命令安装某个命令到的目录的绝对路径。可以执行go list -f '{{.Target}}'命令查看当前项目的默认安装路径

GOCACHE:是一个目录的绝对路径,go命令将在该目录缓存信息以供未来构建程序使用。

GOMODCACHE:是一个目录的绝对路径,go命令把下载的模块缓存在该目录里。

GODEBUG:启用多种调式方式。运行go doc runtime查看相关信息。

GOENV:是一个文件的绝对路径,Go环境变量存储在该文件里。不能使用go env -w命令改变GOENV的值。可以设置GOENV=off来禁用默认的该配置文件。

GOFLAGS:默认会应用于go命令的通过-flag=value设置的以空格分隔的一个选项列表,当然当前go命令会忽略不认识的选项。每个条目都必须是一个独立的选项。由于条目以空格分隔,因此选项的值本身不得包含空格。命令行上列出的选项将于该列表之后应用,因此某些选项会覆盖该列表里给出的选项。

GOINSECURE:以逗号分隔的模块路径前缀的glob模式列表(见Go的path.Match语法),这些模块应始终以不安全的方式获取。仅适用于直接获取的依赖项。GOINSECURE不禁用校验和数据库验证,可以通过GOPRIVATEGONOSUMDB实现这一点。

GOOS:编译Go代码到的操作系统,例如linux、darwin、windows、netbsd等。

GOPATH:更多信息参见go help gopath的输出信息。

GOPROXY:Go模块的代理服务的地址,更多信息见 https://golang.org/ref/mod#environment-variables和https://golang.org/ref/mod#module-proxy。

GOPRIVATE, GONOPROXY, GONOSUMDB:逗号分隔的模块路径前缀的一个列表(具体语法见path.Match函数的文档),这些模块总是被直接获取或者不应该使用校验和数据库验证模块的完整性。

GOROOT:Go在操作系统里的安装路径。

GOSUMDB:使用的校验和数据库验的名字以及它的公钥和URL。

GOTMPDIR:一个目录的路径,go命令在该目录里存储临时代码文件、包和二进制文件。

GOVCS:版本控制命令的一个列表,可能被用于匹配相应的版本控制的服务器,更多信息见go help vcs的输出。

GOWORK:在模块模式下,使用给定的go.work文件作为工作空间文件。默认情况下,或者当GOWORK环境变量的值为“auto”时,go命令在当前目录中搜索名为go.work的文件,然后搜索子目录,直到找到一个go.work文件为止。如果找到一个有效的go.work文件,则其内指定的模块将共同作为主(main)模块。如果GOWORK处于“off”状态,或者在“auto”状态下找不到go.work文件,则不启用工作空间模式。

二、cgo使用的环境变量

AR:使用gccgo编译器构建时用于操作库文件的命令。默认值为“ar”。

CC:用于编译C代码的命令。

CGO_ENABLED:是否启用cgo命令。0或1。

CGO_CFLAGS:当编译C代码时,传递给编译器的标志。

CGO_CFLAGS_ALLOW:一个正则表达式,指定允许出现在#cgo CFLAGS源代码指令中的其他标志。不适用于CGO_CFLAGS环境变量。

CGO_CFLAGS_DISALLOW:一个正则表达式,指定不允许出现在#cgo CFLAGS源代码指令中的其他标志。不适用于CGO_CFLAGS环境变量。

CGO_CPPFLAGS, CGO_CPPFLAGS_ALLOW, CGO_CPPFLAGS_DISALLOW:类似于CGO_CFLAGS、CGO_CFLAGS_ALLOW和CGO_CFLAGS_DISALLOW,但是用于C++预处理器。

CGO_CXXFLAGS, CGO_CXXFLAGS_ALLOW, CGO_CXXFLAGS_DISALLOW:类似于CGO_CFLAGS、CGO_CFLAGS_ALLOW和CGO_CFLAGS_DISALLOW,但是用于C++编译器。

CGO_FFLAGS, CGO_FFLAGS_ALLOW, CGO_FFLAGS_DISALLOW:类似于CGO_CFLAGS、CGO_CFLAGS_ALLOW和CGO_CFLAGS_DISALLOW,但是用于Fortran编译器。

CGO_LDFLAGS, CGO_LDFLAGS_ALLOW, CGO_LDFLAGS_DISALLOW:类似于CGO_CFLAGS、CGO_CFLAGS_ALLOW和CGO_CFLAGS_DISALLOW,但是用于连接器。

CXX:用于C++代码的命令。

FC:用于Fortran代码的命令。

PKG_CONFIG:pkg-config工具的路径。

三、计算机体系结构相关的环境变量

GOARM:如果设置了GOARCH=arm,那么将把Go代码编译为ARM架构CPU的指令。GOARM合法的值有5,6或7。

GO386:如果设置了GOARCH=386,那么GO386用于指示如何实现浮点指令。GO386合法的值有sse2(默认)或softfloat。

GOAMD64:如果设置了GOARCH=amd64,那么将把Go代码编译为64位CPU架构的指令。GOAMD64合法的值有v1(默认),v2,v3或v4。

GOMIPS:如果设置了GOARCH=mips或mipsle,那么GOMIPS用于指示使用哪一种浮点指令。GOMIPS合法的值有hardfloat(默认)或softfloat。

GOMIPS64:如果设置了GOARCH=mips64或mips64le,那么GOMIPS64用于指示使用哪一种浮点指令。GOMIPS64合法的值有hardfloat(默认)或softfloat。

GOPPC64:如果设置了GOARCH=ppc64或ppc64le,那么GOPPC64用于指示使用哪一种ISA(指令集架构)。GOPPC64合法的值有power8(默认)或power9。

GOWASM:如果设置了GOARCH=wasm,那么可以使用一个半角逗号分隔值的列表,列出要使用的WebAssembly特性。GOWASM合法的值有satconv或signext。

四、特殊目的的环境变量

GCCGOTOOLDIR:gccgo工具所在目录的路径,例如cgo,取决于gccgo是如何配置的。

GOEXPERIMENT:一个半角逗号分隔列表,元素值是要启用或禁用的工具链的实验性功能。可用实验性功能的列表可能随时间任意变化。有关当前有效值,请参阅src/internal/goexperiment/flags.go。警告:此变量是为Go工具链本身的开发和测试提供的。不支持超出该用途的使用。

GOROOT_FINAL:指出Go安装目录的路径,当Go的安装路径和构建路径不同时。在栈跟踪信息中的Go内建库的文件名将从GOROOT的值被改写为GOROOT_FINAL的值。

GO_EXTLINK_ENABLED:指示连接器是否使用外部链接模式,当cgo使用-linkmode=auto选项来链接代码时。值为0表示禁用外部链接模式,值为1表示启用。

GIT_ALLOW_PROTOCOL:由Git定义。允许与git fetch/clone一起使用的以冒号分隔的方案列表。如果设置了,任何未明确提及的方案都将被“go get”认为是不安全的。因为变量是由Git定义的,所以不能通过go-env-w设置该环境变量的默认值。

五、其他可从“go env”获得,但不能从环境中读取的信息

GOEXE:可执行文件的后缀名,在Windows里是”.exe”,在其他操作系统里没有后缀名。

GOGCCFLAGS:提供给CC命令的以空格分隔的参数列表。

GOHOSTARCH:Go工具链二进制文件的体系结构(GOARCH)。

GOHOSTOS:Go工具链二进制文件的操作系统(GOOS)。

GOMOD:在Go项目所在目录或子目录下执行go env,可在输出中看到GOMOD的值是当前主模块的go.mod文件的绝对路径。如果启用了模块模式,但还没有写出go.mod文件,则GOMOD的值将为os.DevNull(在类Unix系统上为“/dev/null”,在Windows上为“NUL”)。如果禁用模块模式,GOMOD将为空字符串。

GOTOOLDIR:go工具(编译器,文档等)安装目录的路径。

GOVERSION:当前安装和使用的Go的版本,也可从runtime.Version获取到。

六、go env命令的用法和功能

$ go help env
usage: go env [-json] [-u] [-w] [var ...]

用法:go env [-json] [-u] [-w] [var …]

该命令输出Go环境变量信息。

默认情况下,env将信息打印为shell脚本(在Windows上,为批处理文件)的语法格式。如果给定一个或多个变量名作为参数,env会在每一行中打印每个变量的值。

-json标志表示以JSON格式打印输出Go环境变量信息,而不是以shell脚本(在Windows上,为批处理文件)的格式。

-u标志需要一个或多个变量名作为参数,并取消设置这些环境变量的默认值(如果其中一个已通过go env -w设置了值的话)。

-w标志需要一个或多个形式为NAME=VALUE的参数,并将环境变量NAME的当前值更改为给定值。

如何限制go程序能使用的CPU核数?

一、在编译阶段(go build)做不到限制go程序能使用的CPU核数

因为在编译阶段(go build):

  • 不知道程序将运行在哪台机器
  • 不知道有多少 CPU、是否在容器中
  • Go 编译产物是 通用二进制,不绑定运行环境

所以 不存在编译期的 CPU 限制选项。

编译参数:

  • -gcflags
  • -ldflags
  • GOARCH / GOOS

都不能限制 CPU 核数。

二、官方 & 推荐的运行时方式(进程内)

1 环境变量(最常用)

GOMAXPROCS=4 ./app

限制4个CPU核数,等价于代码:runtime.GOMAXPROCS(4)

无需改代码

进程启动时生效

Go 1.5+ 支持

Go 1.21+ 默认会自动感知容器 CPU 限额

2 代码里设置

runtime.GOMAXPROCS(4)

只能影响 Go 调度器

不限制 OS 线程的创建(那是另一回事)。

三、操作系统 / 容器层(更“硬”的限制)

1 Docker / Kubernetes(强烈推荐)

Docker:

docker run --cpus=2 my-go-app

Kubernetes:

resources:
  limits:
    cpu: "2"

Go runtime 会:

  • 看到 cgroup 限制
  • 自动设置 GOMAXPROCS = 2(Go 1.21+)

2 Linux taskset(CPU 亲和性)

taskset -c 0,1 ./app

限制进程只能跑在 CPU 0、1

对所有语言生效

Go runtime 会“被动服从”

3 cgroups(底层方式)

echo 200000 > cpu.cfs_quota_us
echo 100000 > cpu.cfs_period_us

容器本质用的就是这种方式

最底层、最硬核

同时开启10万个goroutine最少占用多少内存?

我们来一步步拆解实际能达到的最小内存占用。

1. 每个 goroutine 的核心内存组成(最小情况)

部分大小(字节)说明
goroutine 结构体 (g)≈ 300–400 字节包含调度信息、指针、状态等(精确值随版本小幅波动)
初始栈(stack)2 KiB = 2048 字节当前绝大多数平台的最小初始栈(_StackMin)
其他运行时开销≈ 100–300 字节包含 defer 链表指针、panic 记录、gc bitmap 标记位等
单 goroutine 理论最低≈ 2.4–2.8 KiB最干净的空循环场景下实际能看到的下限

关键点:初始栈就是 2 KiB(不是 2KB 有时被误写成 2048 字节),这是 Go 1.4 以来长期保持的值(少数提案讨论过改成 4 KiB,但截至 2026 年初主流版本仍为 2 KiB)。

2. 10 万个这样的 goroutine 最少占用多少?

计算两种典型现实值:

场景每协程估算10 万协程总计备注
最理想情况(接近理论下限)2.4 KiB240–260 MiB极干净、无额外分配、无 hot/cold 分离、无 PGO、无动态栈调整
更现实的干净空转场景≈ 3–4 KiB300–420 MiB包含少量运行时元数据、GC 扫描位、栈 guard page 对齐等
带 fmt.Println 的版本5–10 KiB+500 MiB – 1 GiB+因为 println 涉及缓冲、反射、字符串常量等,会把栈撑大甚至 grow 一次

结论(最少占用):

不断输出 “hello world” 的 10 万个 goroutine,最小能做到 ≈ 240–280 MiB

(前提是使用最简代码、不带任何缓冲、用 print 而不是 fmt、关闭 race detector、纯 amd64/linux 环境)

3. 最简测试代码(尽量接近最小内存)

package main

import (
    "runtime"
    "time"
)

func main() {
    for i := 0; i < 100_000; i++ {
        go func() {
            for {
                println("hello world")   // 用内置 println 比 fmt 省内存
                // time.Sleep(time.Millisecond)   // 注释掉会更“空转”
            }
        }()
    }

    // 让主协程不退出
    print("created 100k goroutines, RSS ≈ ? \n")
    runtime.GC()
    time.Sleep(30 * time.Second)
}

编译运行后用以下方式观察(最接近“最小”值):

# RSS(常驻内存)通常最接近你关心的值
watch -n 1 "ps -o pid,rss,cmd -p $(pgrep -f your-binary) | tail -1"

# 或者用 pprof 查看更精确的 /memory/classes/heap/stacks:bytes
go tool pprof http://localhost:6060/debug/pprof/heap

4. 实际观测到的典型范围

  • 纯 for { println(“hello world”) }:通常 320–480 MiB
  • 如果把 println 去掉,只 for {}:可降到 240–320 MiB
  • 如果改成 for { time.Sleep(time.Second) }:更接近 250–300 MiB

总结一句话:

10 万个只是不停输出 “hello world” 的 goroutine,最少能压到大约 240–280 MiB 左右(理想干净场景下),现实干净代码一般落在 300–450 MiB 区间。

Ubuntu 24安装最新版的Go语言开发环境的方法

Ubuntu 24.04(Noble Numbat)上安装 Go 语言有几种常见方式,2025-2026 年最推荐的方式是直接使用官方二进制包,这样可以拿到最新版本(目前通常是 1.24.x 或 1.25.x),而且最稳定、最容易升级。

下面给出目前最主流、最推荐的安装步骤:

推荐方式:官方二进制安装(最新版,强烈推荐)

1 打开终端,先清理旧版本(非常重要,避免冲突)

sudo rm -rf /usr/local/go

2 去官网查看最新版本(很重要!)

https://go.dev/dl

截至2026年1月,最新稳定版大概率是 go1.25.x 或更高。以 amd64 架构为例(绝大多数电脑都是这个),复制最新版下载链接。

示例(请替换成你看到的最新版):

# 进入下载目录(也可以随便哪个目录)
cd ~/Downloads

# 下载(把版本号改成最新的)
wget https://go.dev/dl/go1.25.6.linux-amd64.tar.gz

3 解压到 /usr/local(官方推荐位置)

sudo tar -C /usr/local -xzf go1.25.6.linux-amd64.tar.gz

4 把 Go 加到 PATH(永久生效):

# 打开配置文件(zsh 用 .zshrc,bash 用 .bashrc)
vim ~/.bashrc

在文件末尾加入这一行:

export PATH=$PATH:/usr/local/go/bin

也可以把go程序的默认安装目录(执行go install 模块名命令)$HOME/go/bin加入PATH环境变量。

保存退出后,立即生效:

source ~/.bashrc

5 验证安装是否成功

go version

应该看到类似输出:

go version go1.25.6 linux/amd64

再检查Go环境变量是否正常:

go env

其他可选的Go语言安装方式

1 sudo apt install golang-go # 从Ubuntu 默认仓库安装,但版本偏旧

2 PPA: longsleep/golang-backports # 版本比较新

3 sudo snap install go –classic # 版本比较新,snap启动稍慢,路径较奇怪

Tips

  • 想升级Go → 直接重复上面步骤,先删掉旧的 /usr/local/go,再下载新版覆盖即可。
  • 多版本共存 → 推荐使用 asdfmise 版本管理工具。
  • 公司/团队要求特定版本 → 也建议用 asdf/mise,而不是全局覆盖。

Go安全

本文翻译自《Security》。

此页面为Go开发人员提供一些资源,以提高Go项目的安全性。

(另请参阅:Go开发人员应该知道的Go项目安全最佳实践。)

查找并修复已知的安全漏洞

Go的漏洞检测旨在为开发人员提供低噪声、可靠的工具,以了解可能影响其项目的已知漏洞。有关概述,请从Go漏洞管理体系架构和常见问题页面开始。对于应用方法,请探索以下工具。

使用govulcheck扫描代码以查找漏洞

开发人员可以使用govulcheck工具来确定是否有任何已知的漏洞会影响他们的代码,并根据实际调用的有安全漏洞的函数和方法来确定下一步先做什么。

在编辑器中检测漏洞

VS Code Go扩展可以检查第三方依赖项并发现相关漏洞。

查找你的项目用到的Go模块

Pkg.go.dev是一个用于发现、评估和学习有关go包和模块的更多信息的网站。在pkg.go.dev上发现和评估go包时,如果该版本存在漏洞,你会在页面顶部看到一条横幅。此外,你可以在go包的版本历史页面上看到影响某个版本的它的安全漏洞有哪些。

浏览安全漏洞数据库

Go漏洞数据库直接从Go包维护者以及MITRE和GitHub等外部来源收集数据。报告由Go Security团队策划。

报告Go项目中的安全漏洞

有关如何报告Go项目中的安全漏洞的说明,请参阅Go安全策略。该文章还详细介绍了Go安全团队跟踪问题并向公众披露的过程。有关过去的修复安全漏洞的记录的详细信息,请参阅发布历史记录。根据发布策略,我们在Go包的两个最新主版本上进行安全修复。

使用模糊测试发现意外输入

Go原生提供的模糊测试是一种自动测试,它不断地往程序的入数据来发现Bug。从Go 1.18开始,标准工具链加入模糊测试工具。也可以使用OSS fuzz,它支持原生的Go模糊测试。

使用Go的加密库提供的安全服务

Go的加密库旨在帮助开发人员构建安全的应用程序。请参阅有关加密的Go包golang.org/x/crypto/的文档

教程:使用govulncheck发现和修复有安全问题的依赖项

本文翻译自《Tutorial: Find and fix vulnerable dependencies with govulncheck》。

Govulncheck是一个低噪音的工具,可以帮助你发现并修复Go项目中易受攻击的依赖项。它通过扫描项目的依赖项以查找已知的漏洞,并识别出对这些漏洞的任何直接或间接调用的项目代码。

在本教程中,你将学习如何使用govulcheck扫描一个简单的程序以查找漏洞,如何对漏洞进行优先级排序和评估,以便首先集中精力修复最重要的漏洞。

要了解更多关于govulcheck的信息,请参阅govulceck文档和这篇关于Go漏洞管理的博客文章。我们也很乐意听取你的反馈。

先决条件

  • 使用Go 1.18或更高版本。Govulncheck旨在与Go 1.18及以后的版本配合使用。我们建议使用最新版本的Go来遵循本教程。(有关安装Go的说明,请参阅安装Go。)
  • 一个代码编辑器。任何文本编辑都可以很好地工作。
  • 一个命令终端。Go在Linux和Mac的终端程序,以及Windows中的PowerShell或cmd上都能很好地工作。

本教程将带你完成以下步骤:

1 创建一个Go模块示例,它的某个依赖项有漏洞

2 安装并运行govulcheck

3 评估漏洞 4 升级并修复有漏洞的依赖项

创建一个Go模块示例

步骤1,首先,创建一个名为vulntutorial的新文件夹并初始化Go模块。例如,从当前目录运行以下命令:

$ mkdir vuln-tutorial
$ cd vuln-tutorial
$ go mod init vuln.tutorial

步骤2,在vuln-tutorial文件夹中创建一个名为main.go的文件,并将以下代码复制到其中:

package main

import (
        "fmt"
        "os"

        "golang.org/x/text/language"
)

func main() {
        for _, arg := range os.Args[1:] {
                tag, err := language.Parse(arg)
                if err != nil {
                        fmt.Printf("%s: error: %v\n", arg, err)
                } else if tag == language.Und {
                        fmt.Printf("%s: undefined\n", arg)
                } else {
                        fmt.Printf("%s: tag %s\n", arg, tag)
                }
        }
}

此示例程序将语言标签的一个列表作为命令行参数,并为每个标签打印一条消息,指示标签是否解析成功、是否未定义或者解析标签时是否出错。

步骤3,运行go mod tidy命令,把main.go的代码所需的所有依赖项记录到go.mod文件。在vuln-tutorial文件夹所在目录,运行以下命令:

$ go mod tidy

你应该能看到类似如下输出:

go: finding module for package golang.org/x/text/language
go: downloading golang.org/x/text v0.9.0
go: found golang.org/x/text/language in golang.org/x/text v0.9.0

第4步,打开go.mod文件,它的内容应该如下所示:

module vuln.tutorial

go 1.20

require golang.org/x/text v0.9.0

第5步,降级golang.org/x/text依赖项的版本到v0.3.5,这个版本包含一个众所周知的安全漏洞:

$ go get golang.org/x/text@v0.3.5

你应该能看到类似如下输出:

go: downgraded golang.org/x/text v0.9.0 => v0.3.5

打开go.mod文件,它的内容应该如下所示:

module vuln.tutorial

go 1.20

require golang.org/x/text v0.3.5

接下来我们使用govulncheck来发现vuln-tutorial项目中的安全漏洞。

安装并运行govulncheck

第6步,使用go install命令安装govulncheck:

$ go install golang.org/x/vuln/cmd/govulncheck@latest

第7步,在vuln-tutorial目录里运行govulncheck来分析vuln-tutorial项目中的安全漏洞:

$ govulncheck ./...

你应该会看到如下输出:

govulncheck is an experimental tool. Share feedback at https://go.dev/s/govulncheck-feedback.

Using go1.20.3 and govulncheck@v0.0.0 with
vulnerability data from https://vuln.go.dev (last modified 2023-04-18 21:32:26 +0000 UTC).

Scanning your code and 46 packages across 1 dependent module for known vulnerabilities...
Your code is affected by 1 vulnerability from 1 module.

Vulnerability #1: GO-2021-0113
  Due to improper index calculation, an incorrectly formatted
  language tag can cause Parse to panic via an out of bounds read.
  If Parse is used to process untrusted user inputs, this may be
  used as a vector for a denial of service attack.

  More info: https://pkg.go.dev/vuln/GO-2021-0113

  Module: golang.org/x/text
    Found in: golang.org/x/text@v0.3.5
    Fixed in: golang.org/x/text@v0.3.7

    Call stacks in your code:
      main.go:12:29: vuln.tutorial.main calls golang.org/x/text/language.Parse

=== Informational ===

Found 1 vulnerability in packages that you import, but there are no call
stacks leading to the use of this vulnerability. You may not need to
take any action. See https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck
for details.

Vulnerability #1: GO-2022-1059
  An attacker may cause a denial of service by crafting an
  Accept-Language header which ParseAcceptLanguage will take
  significant time to parse.
  More info: https://pkg.go.dev/vuln/GO-2022-1059
  Found in: golang.org/x/text@v0.3.5
  Fixed in: golang.org/x/text@v0.3.8

解释一下上述输出

注意,不同Go版本,上述输出可能不同。

我们的代码受到漏洞GO-2021-0113的影响,因为它直接调用golang.org/x/text/language的Parse函数,而这个函数在v0.3.5版本存在安全漏洞。

golang.org/x/text模块v0.3.5中存在另一个漏洞GO-2022-1059。然而,它被报告为“Informational”,因为我们的代码没有(直接或间接)调用这个安全漏洞相关的函数。

现在,让我们评估vuln-tutorial项目中的漏洞并确定要采取的行动。

评估漏洞

a.评估漏洞

首先,阅读漏洞的描述信息,并确定它是否真的适用于你的代码和用例。如果你需要更多信息,请访问“More info”链接。

根据描述,漏洞GO-2021-0113在使用Parse函数处理不受信任的用户输入时可能会引发panic。假设我们打算让我们的程序承受不受信任的输入,那么该漏洞可能就会被利用。

漏洞GO-2022-1059不会影响我们的代码,因为我们的代码没有从该依赖项中调用任何有安全漏洞的函数。

b.决定采取什么行动

为了解决GO-2021-0113漏洞问题,我们有以下几个选择:

选项1:升级到修复后的版本。如果有可用的修复,我们可以通过升级到该模块的修复版本来删除安全漏洞。

选项2:停止使用有安全漏洞的标识符。我们可以删除代码中对有安全漏洞的函数的所有调用。但我们需要找到一个替代方案,或者自己实现相关函数。

在本例情况下,我们可以使用修复后的版本,Parse函数是我们程序不可或缺的一部分。让我们将依赖项升级到“fixed in”版本v0.3.7。

漏洞GO-2022-1059与漏洞GO-2021-0113在同一模块中,而且它的修复版本是v0.3.8,所以我们可以通过升级到v0.3.8轻松地同时删除这两个漏洞。

升级并修复有安全漏洞的依赖项

幸运的是,升级并修复有安全漏洞的依赖项非常简单。

第8步,升级golang.org/x/text至v0.3.8版本:

$ go get golang.org/x/text@v0.3.8

你应该能看到如下输出:

go: upgraded golang.org/x/text v0.3.5 => v0.3.8

请注意,我们也可以选择升级到最新版本,或v0.3.8之后的任何其他版本。

第9步,现在再次运行govulcheck:

$ govulncheck ./...

你现在会看到如下输出:

govulncheck is an experimental tool. Share feedback at https://go.dev/s/govulncheck-feedback.

Using go1.20.3 and govulncheck@v0.0.0 with
vulnerability data from https://vuln.go.dev (last modified 2023-04-06 19:19:26 +0000 UTC).

Scanning your code and 46 packages across 1 dependent module for known vulnerabilities...
No vulnerabilities found.

govuncheck确认没有发现漏洞。

使用命令govulcheck定期扫描依赖项,你可以识别、排序和解决安全漏洞来保护你的项目代码。

Go安全政策

本文翻译自《Go Security Policy》。

概述

本文档介绍Go Security团队处理报告的问题的流程以及预期的回复。

报告一个安全漏洞

Go发行版中的所有安全漏洞都应通过电子邮件报告给security@golang.org。此邮件会发送给Go Security团队。

为了确保你的报告不被标记为垃圾邮件,请在电子邮件中的任何位置包含“vulnerability”一词。请在电子邮件中使用一行描述主题。

你的电子邮件将在7天内得到确认,在解决问题之前,你将了解最新进展。你的问题将在90天内解决或公开。

如果你在7天内没有收到电子邮件回复,请再次与Go安全团队联系,地址为security@golang.org。请确保你的电子邮件中包含“vulnerability”一词。

如果再过3天,你仍未收到对报告的确认,则你的电子邮件可能已被标记为垃圾邮件。在这种情况下,请在此处提交问题。选择“我想报告谷歌产品(SQLi、XSS等)中的技术安全或滥用风险相关的错误”,并选中“Go”为受影响的产品。

跟踪问题

根据问题的性质,Go安全团队会将其归类为PUBLIC、PRIVATE或URGENT问题。所有安全问题都将被分配一个CVE编号。

PUBLIC

PUBLIC的问题影响非常有限,或者已经广为人知。

PUBLIC的问题被标记为“Proposal-Security”,通过公开的Go提案审查过程进行讨论,并返回到下一个计划的次要发布(minor releases)(每月发布一次)。发布公告包括这些问题的详细信息,但不会预先发布。

以下是过去发布的PUBLIC的问题的例子:

  • #44916:archive/zip:调用Reader.Open时可能会引发panic
  • #44913:encoding/xml:把自定义TokenReader传给xml.NewTokenDecoder时会引发无限循环
  • #40928: net/http/cgi,net/http/fcgi:但没有指定Content-Type时存在Cross-Site Scripting (XSS)攻击风险
  • #40618: encoding/binary: ReadUvarint和ReadVarint可以从非法输入中读取无限个字节
  • #36834: crypto/x509:Windows 10可以绕过证书验证

PRIVATE

PRIVATE中的问题违反了已提交的安全属性。

PRIVATE问题在下一个计划发布的次要版本中得到修复,并在此之前保持私有状态。

发布前三到七天,将发布预公告,宣布即将发布的版本中存在一个或多个安全修复程序,以及这些问题是否会影响标准库或(和)工具链,以及每个修复程序的CVE ID号码。

以下是过去发布的RIVATE的问题的例子:

  • #53416: path/filepath: Glob包会导致栈空间耗尽
  • #53616: go/parser:所有Parse*函数都存在栈空间耗尽的问题
  • #54658: net/http:GOAWAY发送GOAWAY给服务器后引发错误
  • #56284: syscall, os/exec:在环境变量中没有清除NUL

URGENT

URGENT问题对Go的生态系统的完整性构成威胁,或者正在被黑客积极利用,导致严重破坏。虽然最近没有这方面的例子,但它们可能包括net/http中的远程代码执行,或crypto/tls中的密钥恢复等。

URGENT问题是私下解决的,并会立即进行安全版本的发布,可能不会有预公告。

发送安全相关问题

如果你认为现有的某个问题与安全相关,我们请求你发送电子邮件至security@golang.org。电子邮件应包括问题ID和为什么应根据此安全策略进行处理的简短描述。

披露和处理一个安全漏洞的流程

Go使用以下流程来披露和处理一个安全漏洞的流程:

  • 一旦收到一个安全报告,就会为其分配一个主处理流程。有个人负责协调整个修复和发布过程。
  • 问题已得到确认,并确定了受影响软件的列表。
  • 对代码进行审计,以发现任何潜在的类似问题。
  • 如果在与提交者协商后确定需要CVE编号,则主处理流程将获得一个。
  • 为最近的两个主版本号和head/master分支准备好修复程序。修复程序是为最近的两个主版本号准备的,并合并到head/master分支中。
  • 在应用修复程序的当天,会有公告发送到golang-announcement、golang-dev和golang-nuts。

这个过程可能需要一些时间,尤其是当需要与其他项目的维护人员进行协调时。我们将尽一切努力及时处理漏洞,但重要的是,我们要遵循上述流程,确保披露的漏洞得到一致的处理过程。

对于包括分配CVE号码在内的安全问题,该问题会在CVE详细信息网站国家漏洞披露网站的“Golang”产品下公开列出。

接收安全更新

接收安全公告的最佳方式是订阅golang-announce邮件列表。任何与安全问题有关的消息都将以[security]作为前缀。

对此政策的评论

如果你对改进此Go安全政策有任何建议,请提交一个问题进行讨论。

Go开发人员应该知道的Go项目安全最佳实践

本文翻译自《Security Best Practices for Go Developers》。

点此回到《Go安全》。

此页面为Go开发人员提供了优先考虑项目安全的最佳实践。从使用自动化的模糊测试到轻松检查竞态条件(race condition),这些技巧可以帮助你的代码库更加安全可靠。

扫描源代码和二进制文件中的漏洞

定期扫描代码和二进制文件中的漏洞有助于及早发现潜在的安全风险。你可以使用由Go漏洞数据库支持的govulcheck来扫描代码中的漏洞,并分析哪些漏洞会真正影响到你。开始学习govuncheck教程

Govulncheck也可以集成到CI/CD工作流中。Go团队在GitHub Marketplace上为Govulcheck提供了一个GitHub动作( GitHub Action)。Govulncheck还支持-json标志,以帮助开发人员将漏洞扫描功能与其他CI/CD系统集成。

你还可以使用VS Code的Go扩展直接在编辑器中扫描漏洞。见本教程

使你的Go版本和依赖项保持最新

让你的Go版本保持最新,你就可以使用最新的语言功能、性能改进和已知安全漏洞的修补程序。更新的Go版本还确保了与新版本的依赖项的兼容性,有助于避免潜在的集成问题。查看Go版本的历史发布记录,查看在不同版本之间对Go进行了哪些更改。Go团队在整个发布周期中按照安全问题的议点发布,以解决安全漏洞。请确保更新到最新的Go的小版本号,以确保你拥有最新的安全修复程序。

维护最新的第三方依赖项对于Go生态系统中的软件的安全性、性能和遵守最新标准都至关重要。然而,在没有彻底审查的情况下更新到最新版本也可能存在风险,可能会引入新的Bug、不兼容的更改,甚至恶意代码。因此,虽然更新到最新的安全补丁和改进的依赖项至关重要,但每次更新都应该仔细审查和测试。

使用模糊测试来发现代码的边界漏洞

模糊测试是一种自动测试,它使用覆盖率导向(coverage guidance)来操纵随机输入并遍历代码,以发现和报告潜在的漏洞,例如SQL注入、缓冲区溢出、拒绝服务以及跨站点脚本攻击。模糊测试经常会触及程序员错过的边界测试用例,或者认为不太可能出错的边界测试用例。见本教程

使用Go的竞态检测器检查竞态情况

当两个或多个goroutine同时访问同一资源,并且其中至少有一个访问是写操作时,就会出现竞态情况。这可能会导致软件中出现不可预测、难以诊断的问题。使用内置的竞态检测器在Go代码中识别潜在的竞态情况,这可以帮助你确保并发程序的安全性和可靠性。不过,竞态检测器只会查找运行时发生的争用,没法在未执行的代码中查找。

要使用内置的竞态检测器,请在运行测试或构建应用程序时添加-race标志,例如go test -race。这将在启用竞态检测器的情况下编译代码,并报告它在运行时检测到的任何竞态情况。当竞态检测器在程序中发现数据冲突时,它将打印一份报告,其中包含冲突访问的堆栈跟踪,以及创建相关goroutine的堆栈。

使用Vet检查可疑的代码结构

Go的vet命令旨在分析源代码,并标记不一定是语法错误,但可能在运行时导致问题的潜在代码,例如无法访问到的代码、未使用的变量以及goroutine中常见的错误。在开发过程的早期发现这些问题,有助于保持代码质量,减少调试时间,并提高软件的整体可靠性。要为指定项目运行go vet,请运行:

go vet ./...

译者注:Goland这种IDE已经集成并会自动使用vet命令了。

订阅golang公告以获取安全相关发布的通知

包含安全修复程序的Go版本已预先发布到golang-announce@googlegroups.com邮件列表中。如果你想知道Go本身的安全修复何时开始,请订阅。

Go CNA政策

本文翻译自《Go CNA Policy》。

点此回到《Go安全》。

概述

Go CNA是一个CVE编号机构,负责发布CVE ID并发布Go生态系统中公开漏洞的CVE记录。它是Google CNA的子CNA。

范围

Go CNA涵盖Go项目(Go标准库子存储库)中的漏洞,以及其他CNA尚未涵盖的可导入的Go模块中的公开漏洞。

此范围旨在明确排除Go中编写的应用程序或不可导入的包中的漏洞(例如main中的任何包)。更多信息,请参阅go.dev/security/vuln/database#excluded-reports。

要报告Go项目中潜在的新漏洞,请参阅Go.dev/security/policy。

为一个公开漏洞请求一个CVE ID

重要提示:下面链接的表单在议题跟踪器上创建了一个公开议题,因此不得用于报告Go中未公开的漏洞(有关报告未公开问题的说明,请参阅我们的安全政策)。

要为Go生态系统中现有PUBLIC漏洞请求一个CVE ID,请通过此表单提交请求

如果漏洞已经公开披露,或者存在于你维护的包中,并且你准备公开披露,则该漏洞被视为公开漏洞。

Go漏洞管理

本文翻译自《Go Vulnerability Management》。

点此回到《Go安全》

概述

Go可以帮助开发人员检测、评估和解决有可能被攻击者利用的代码Bug或弱点。在幕后,Go团队运行一个管道来策划有关漏洞的报告,这些报告存储在Go漏洞数据库中。可以阅读和分析各种库和工具的这些报告,以了解特定用户项目可能受到的影响。此功能已集成到Go软件包发现站点和新的CLI工具govulcheck中。

该项目正在推进中,正在积极开发中。我们欢迎你的反馈,帮助我们改进!

注意:要报告Go项目中的漏洞,请参阅Go安全策略

架构

Go中的漏洞管理由以下高级部分组成:

资源

Go漏洞数据库

Go漏洞数据库包含来自许多现有来源的信息,此外还有Go包的维护人员直接向Go安全团队的报告。数据库中的每个条目都会被审查,以确保漏洞的描述、包和符号的信息以及版本的详细信息是准确的。

有关go漏洞数据库的更多信息,请参阅go.dev/security/vuln/database,在浏览器中查看数据库中的漏洞信息,请参阅pkg.go.dev/vuln

我们鼓励包的维护人员在自己的项目中提供有关漏洞的信息,并向我们发送如何减少该漏洞造成的影响的建议

Go漏洞检测

Go的漏洞检测旨在为Go用户提供一种低噪声、可靠的方式来了解可能影响其项目的已知漏洞。漏洞检测集成到Go的工具和服务中,包括一个新的命令行工具govulcheckGo包发现网站主流的编辑器,例如带有Go扩展的VS Code。

要开始使用govulcheck,请在项目中运行以下命令语句:

$ go install golang.org/x/vuln/cmd/govulncheck@latest
$ govulncheck ./...

要在编辑器中启用漏洞检测,请参阅编辑器集成漏洞检测插件页面中的说明。

Go CNA

Go安全团队是一个CVE编号机构(CVE Numbering Authority)。有关更多信息,请参阅go.dev/security/vuln/cna

反馈

我们希望你在以下方面做出贡献并帮助我们改进:

FAQ

如何报告Go项目中的漏洞?

通过电子邮件向security@golang.org报告Go项目中的所有安全漏洞。有关我们流程的更多信息,请阅读Go的安全政策

如何将公共漏洞添加到Go漏洞数据库?

要将公共漏洞添加到Go漏洞数据库,请填写此表单

如果漏洞已经公开披露,或者存在于你维护的包中(并且你已准备好披露),则该漏洞被视为公开漏洞。该表单仅适用于不由Go团队维护的可导入的Go包中的公共漏洞(Go标准库、Go工具链和golang.org模块之外的任何包)。

该表单也可用于申请新的CVE ID。点击此处了解更多关于Go CVE编号机构的信息。

如何提议对漏洞进行编辑?

提议编辑Go漏洞数据库中的现有报告,请填写此处的表单

我如何报告问题或提供有关govulcheck的反馈?

Go问题跟踪器上提交你的问题或反馈。

我在另一个数据库中发现了此漏洞,为什么它不在Go漏洞数据库中?

由于各种原因,报告可能会被排除在Go漏洞数据库之外,包括相关漏洞不存在于Go包中,存在于可安装命令而非可导入包中,或者该漏洞被数据库中已存在的另一个漏洞所包含。你可以在此处了解更多关于Go Security团队排除报告的原因。如果你认为某个报告被错误地排除在vuln.gov之外,请告诉我们

为什么Go漏洞数据库不使用严重级别标签?

大多数漏洞报告格式使用严重性标签,如“LOW”、“MEDIUM”和“CRITICAL”,以指示不同漏洞造成的影响程度,并帮助开发人员确定安全问题的优先处理级别。然而,由于几个原因,Go避免使用此类标签。

漏洞的影响很少是普遍的,这意味着严重性指标往往具有欺骗性。例如,如果解析器用于解析用户提供的输入,并且可以被DoS攻击利用,那么解析器中的漏洞可能是一个严重的问题,但如果解析器只是用于分析本地配置文件,即使将严重性称为“低”也可能言过其实。

严重程度也必然是主观的。即使对于CVE程序也是如此,该程序假定了一个公式来分解漏洞的相关方面,如攻击向量、复杂性和可利用性。然而,所有这些都需要主观评价。

我们认为,对漏洞的良好描述比严重性指标更有用。一个好的描述可以分解什么是问题,如何触发问题,以及用户在确定对自己软件的影响时应该考虑什么。

如果你想与我们分享你对此主题的想法,请随时提交一个议题