教學:使用 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/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.org.tw/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)。

另一個漏洞,GO-2022-1059,存在於 `golang.org/x/text` 模組的 v0.3.5 中。然而,它被報告為「資訊性」,因為我們的程式碼從未(直接或間接)呼叫任何有漏洞的函式。

現在,讓我們評估漏洞並決定採取的行動。

評估漏洞

a. 評估漏洞。

首先,請閱讀漏洞說明,並判斷它是否實際適用於您的程式碼和使用案例。如果您需要更多資訊,請前往「更多資訊」連結。

根據說明,漏洞 GO-2021-0113 可能在使用 Parse 處理不可信使用者輸入時造成恐慌。假設我們的程式預計要承受不可信輸入,且我們擔心拒絕服務,因此這個漏洞很可能適用。

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/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.org.tw/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 指令掃描您的依賴項,您可以透過識別、優先處理和解決漏洞來保護您的程式碼庫。