教程:使用 govulncheck 查找和修复易受攻击的依赖项

Govulncheck 是一种低噪音工具,可帮助您在 Go 项目中查找和修复易受攻击的依赖项。它通过扫描项目依赖项以查找已知的漏洞,然后识别代码中对这些漏洞的任何直接或间接调用来实现此目的。

在本教程中,您将学习如何使用 govulncheck 扫描简单的程序以查找漏洞。您还将学习如何对漏洞进行优先级排序和评估,以便您可以首先专注于修复最重要的漏洞。

要了解有关 govulncheck 的更多信息,请参阅 govulncheck 文档,以及 Go 的 关于漏洞管理的博文。我们也希望 收到您的反馈

先决条件

本教程将引导您完成以下步骤

  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/[email protected]

您应该会看到以下输出

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://golang.ac.cn/s/govulncheck-feedback.

Using go1.20.3 and [email protected] 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/[email protected]
    Fixed in: golang.org/x/[email protected]

    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/[email protected]
  Fixed in: golang.org/x/[email protected]

解释输出

*注意:如果您没有使用最新版本的 Go,您可能会看到标准库中的其他漏洞。

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

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

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

评估漏洞

a. 评估漏洞。

首先,阅读漏洞说明并确定它是否确实适用于您的代码和您的用例。如果您需要更多信息,请访问“更多信息”链接。

根据说明,漏洞 GO-2021-0113 在使用 Parse 处理不受信任的用户输入时可能导致 panic。假设我们的程序旨在抵御不受信任的输入,并且我们担心拒绝服务,因此该漏洞可能适用。

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

b. 确定行动方案。

为了缓解 GO-2021-0113,我们有一些选择

在本例中,有一个可用的修复程序,并且 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/[email protected]

您应该会看到以下输出

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://golang.ac.cn/s/govulncheck-feedback.

Using go1.20.3 and [email protected] 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 扫描您的依赖项,您可以通过识别、优先级排序和解决漏洞来保护您的代码库。