Go语言基地

使用 govulncheck 查找并修复易受攻击的依赖项

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

在本教程中,你将学习如何使用 govulncheck 扫描简单程序的漏洞。你还将学习如何优先处理和评估漏洞,以便首先专注于修复最重要的漏洞。

要了解有关 govulncheck 的更多信息,请参阅 govulncheck 文档,以及这篇关于漏洞管理的 博客文章。我们也乐于 听取你的反馈

先决条件

  • Go。 我们建议使用最新版本的 Go 来遵循本教程。(有关安装说明,请参阅 安装 Go。)
  • 代码编辑器。 任何你拥有的编辑器都可以正常工作。
  • 命令终端。 Go 在 Linux 和 Mac 上的任何终端上都能很好地工作,在 Windows 上的 PowerShell 或 cmd 上也是如此。

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

  1. 创建一个包含易受攻击依赖项的示例 Go 模块
  2. 安装并运行 govulncheck
  3. 评估漏洞
  4. 升级易受攻击的依赖项

创建一个包含易受攻击依赖项的示例 Go 模块

步骤 1. 首先,创建一个名为 vuln-tutorial 的新文件夹并初始化一个 Go 模块。 (如果你是 Go 模块的新手,请查看 go.dev/doc/tutorial/create-module。)

例如,从你的主目录运行以下命令:

$ 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 的实际操作。

安装并运行 govulncheck

步骤 6. 使用 go install 命令安装 govulncheck:

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

步骤 7. 从你想分析的文件夹(在这种情况下是 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
  由于索引计算错误,格式不正确的语言标签会导致 Parse 因越界读取而发生恐慌。
  如果 Parse 用于处理不受信任的用户输入,这可能用作拒绝服务攻击的载体。

  更多信息: https://pkg.go.dev/vuln/GO-2021-0113

  模块: golang.org/x/text
    发现于: golang.org/x/text@v0.3.5
    修复于: golang.org/x/text@v0.3.7

    调用栈在你的代码中:
      main.go:12:29: vuln.tutorial.main 调用 golang.org/x/text/language.Parse

=== 信息性漏洞 ===

在你的导入包中发现了 1 个漏洞,但没有调用栈导致使用此漏洞。你可能不需要采取任何行动。详情见 https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck

漏洞 #1: GO-2022-1059
  攻击者可以通过构造一个 Accept-Language 头来导致拒绝服务,ParseAcceptLanguage 将花费大量时间解析。
  更多信息: https://pkg.go.dev/vuln/GO-2022-1059
  发现于: golang.org/x/text@v0.3.5
  修复于: golang.org/x/text@v0.3.8

解释输出

*注意:如果你没有使用最新版本的 Go,你可能会看到来自标准库的额外漏洞。

我们的代码受到一个漏洞的影响, GO-2021-0113,因为它直接调用了 golang.org/x/text/languageParse 函数,且该函数处于易受攻击的版本(v0.3.5)。

另一个漏洞 GO-2022-1059 存在于 golang.org/x/text 模块的 v0.3.5 版本中。然而,它被报告为“信息性”,因为我们的代码从未(直接或间接)调用其任何易受攻击的函数。

现在,让我们评估漏洞并确定要采取的行动。

评估漏洞

a. 评估漏洞。

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

根据描述,漏洞 GO-2021-0113 会在 Parse 用于处理不受信任的用户输入时导致恐慌。假设我们打算让我们的程序能够承受不受信任的输入,并且我们担心拒绝服务,因此该漏洞可能适用。

GO-2022-1059 可能不会影响我们的代码,因为我们的代码不调用该报告中的任何易受攻击的函数。

b. 决定采取的行动。

为了缓解 GO-2021-0113,我们有几个选项:

  • 选项 1: 升级到修复版本。 如果有修复可用,我们可以通过升级到模块的修复版本来移除易受攻击的依赖项。
  • 选项 2: 停止使用易受攻击的符号。 我们可以选择删除代码中对易受攻击函数的所有调用。我们需要找到替代方案或自己实现它。

在这种情况下,修复可用,且 Parse 函数对我们的程序至关重要。让我们将依赖项升级到“修复于”版本 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

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

步骤 9. 现在再次运行 govulncheck:

$ 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.

最后,govulncheck 确认没有发现漏洞。

通过定期使用 govulncheck 扫描你的依赖项,你可以通过识别、优先处理和解决漏洞来保护你的代码库。

On this page