チュートリアル: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.dokyumento.jp/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を使用していない場合、標準ライブラリから追加の脆弱性が表示される場合があります。

私たちのコードは、脆弱なバージョン(v0.3.5)でgolang.org/x/text/languageParse関数を直接呼び出しているため、1つの脆弱性GO-2021-0113の影響を受けます。

別の脆弱性GO-2022-1059は、v0.3.5のgolang.org/x/textモジュールに存在します。ただし、コードが脆弱な関数を(直接または間接的に)呼び出すことはないため、「情報提供」として報告されます。

次に、脆弱性を評価し、講じるアクションを決定しましょう。

脆弱性を評価する

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.dokyumento.jp/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を使用して依存関係を定期的にスキャンすることで、脆弱性を特定、優先順位付け、対処することにより、コードベースを保護できます。