Govulncheck là một công cụ ít gây nhiễu, giúp bạn tìm và sửa các dependency có lỗ hổng trong các dự án Go của mình. Nó làm việc này bằng cách quét các dependency của dự án để tìm những lỗ hổng đã biết, rồi xác định mọi lời gọi trực tiếp hay gián tiếp tới các lỗ hổng đó trong mã của bạn.
Trong hướng dẫn này, bạn sẽ học cách dùng govulncheck để quét một chương trình đơn giản nhằm tìm lỗ hổng. Bạn cũng sẽ học cách sắp xếp mức độ ưu tiên và đánh giá các lỗ hổng, để có thể tập trung sửa những lỗ hổng quan trọng nhất trước.
Để tìm hiểu thêm về govulncheck, hãy xem govulncheck documentation, và blog post on vulnerability management dành cho Go. Chúng tôi cũng rất mong được hear your feedback.
Yêu cầu trước khi bắt đầu
- Go. Chúng tôi khuyên bạn dùng phiên bản Go mới nhất để làm theo hướng dẫn này. Xem hướng dẫn cài đặt tại Installing Go.
- Một trình soạn thảo mã nguồn. Bất kỳ trình soạn thảo nào bạn có cũng đều dùng tốt.
- Một cửa sổ dòng lệnh. Go hoạt động tốt với mọi terminal trên Linux và Mac, và với PowerShell hoặc cmd trên Windows.
Hướng dẫn sẽ đưa bạn qua các bước sau:
- Tạo một module Go mẫu có một dependency chứa lỗ hổng
- Cài đặt và chạy govulncheck
- Đánh giá các lỗ hổng
- Nâng cấp các dependency có lỗ hổng
Tạo một module Go mẫu có một dependency chứa lỗ hổng
Bước 1. Trước tiên, tạo một thư mục mới tên là vuln-tutorial và khởi tạo một module Go. (Nếu bạn mới làm quen với module trong Go, hãy xem go.dev/doc/tutorial/create-module.
Ví dụ, từ thư mục home của bạn, chạy các lệnh sau:
$ mkdir vuln-tutorial
$ cd vuln-tutorial
$ go mod init vuln.tutorial
Bước 2. Tạo một tệp tên là main.go bên trong thư mục vuln-tutorial, rồi chép đoạn mã sau vào đó:
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)
}
}
}
Chương trình mẫu này nhận một danh sách các thẻ ngôn ngữ làm đối số dòng lệnh, rồi in ra một thông báo cho mỗi thẻ, cho biết thẻ đó được phân tích thành công, thẻ không xác định, hay có lỗi xảy ra trong lúc phân tích thẻ.
Bước 3. Chạy go mod tidy, lệnh này sẽ điền vào tệp go.mod tất cả các dependency mà đoạn mã bạn vừa thêm vào main.go ở bước trước cần đến.
Từ thư mục vuln-tutorial, chạy:
$ go mod tidy
Bạn sẽ thấy kết quả này:
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
Bước 4. Mở tệp go.mod của bạn để kiểm tra rằng nó trông như sau:
module vuln.tutorial
go 1.20
require golang.org/x/text v0.9.0
Bước 5. Hạ phiên bản của golang.org/x/text xuống v0.3.5, phiên bản này chứa các lỗ hổng đã biết. Chạy:
$ go get golang.org/x/[email protected]
Bạn sẽ thấy kết quả này:
go: downgraded golang.org/x/text v0.9.0 => v0.3.5
Tệp go.mod bây giờ sẽ có nội dung:
module vuln.tutorial
go 1.20
require golang.org/x/text v0.3.5
Bây giờ, hãy xem govulncheck hoạt động ra sao.
Cài đặt và chạy govulncheck
Bước 6. Cài đặt govulncheck bằng câu lệnh go install:
$ go install golang.org/x/vuln/cmd/govulncheck@latest
Bước 7. Từ thư mục bạn muốn phân tích (trong trường hợp này là vuln-tutorial). Chạy:
$ govulncheck ./...
Bạn sẽ thấy kết quả này:
govulncheck is an experimental tool. Share feedback at https://go.dev/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]
Đọc hiểu kết quả
*Lưu ý: Nếu bạn không dùng phiên bản Go mới nhất, bạn có thể thấy thêm các lỗ hổng từ thư viện chuẩn.
Mã của chúng ta bị ảnh hưởng bởi một lỗ hổng, GO-2021-0113, vì nó gọi trực tiếp hàm Parse của golang.org/x/text/language ở một phiên bản có lỗ hổng (v0.3.5).
Một lỗ hổng khác, GO-2022-1059, tồn tại trong module golang.org/x/text ở phiên bản v0.3.5. Tuy nhiên, nó được báo cáo là “Informational” vì mã của chúng ta không bao giờ gọi (trực tiếp hay gián tiếp) bất kỳ hàm có lỗ hổng nào của nó.
Bây giờ, hãy đánh giá các lỗ hổng và quyết định hành động cần thực hiện.
Đánh giá các lỗ hổng
a. Đánh giá các lỗ hổng.
Trước tiên, hãy đọc mô tả của lỗ hổng và xác định xem nó có thực sự áp dụng cho mã của bạn và trường hợp sử dụng của bạn hay không. Nếu bạn cần thêm thông tin, hãy truy cập liên kết “More info”.
Dựa trên mô tả, lỗ hổng GO-2021-0113 có thể gây panic khi Parse được dùng để xử lý dữ liệu đầu vào không đáng tin từ người dùng. Giả sử chúng ta muốn chương trình của mình chịu được dữ liệu đầu vào không đáng tin, và chúng ta lo ngại về tấn công từ chối dịch vụ, thì lỗ hổng này nhiều khả năng có áp dụng.
GO-2022-1059 nhiều khả năng không ảnh hưởng tới mã của chúng ta, vì mã của chúng ta không gọi bất kỳ hàm có lỗ hổng nào trong báo cáo đó.
b. Quyết định hành động.
Để giảm thiểu GO-2021-0113, chúng ta có vài lựa chọn:
- Lựa chọn 1: Nâng cấp lên một phiên bản đã sửa lỗi. Nếu đã có bản vá, chúng ta có thể loại bỏ một dependency có lỗ hổng bằng cách nâng cấp lên phiên bản đã sửa lỗi của module đó.
- Lựa chọn 2: Ngừng dùng (các) ký hiệu có lỗ hổng. Chúng ta có thể chọn cách bỏ hết các lời gọi tới hàm có lỗ hổng trong mã của mình. Khi đó chúng ta sẽ phải tìm một giải pháp thay thế hoặc tự hiện thực nó.
Trong trường hợp này, đã có bản vá, và hàm Parse là thành phần không thể thiếu của chương trình. Hãy nâng cấp dependency lên phiên bản “fixed in”, v0.3.7.
Chúng ta đã quyết định hạ mức ưu tiên việc sửa lỗ hổng mang tính thông tin, GO-2022-1059, nhưng vì nó nằm trong cùng module với GO-2021-0113, và vì phiên bản sửa lỗi của nó là v0.3.8, nên chúng ta có thể dễ dàng loại bỏ cả hai cùng lúc bằng cách nâng cấp lên v0.3.8.
Nâng cấp các dependency có lỗ hổng
May mắn thay, việc nâng cấp các dependency có lỗ hổng khá đơn giản.
Bước 8. Nâng cấp golang.org/x/text lên v0.3.8:
$ go get golang.org/x/[email protected]
Bạn sẽ thấy kết quả này:
go: upgraded golang.org/x/text v0.3.5 => v0.3.8
(Lưu ý rằng chúng ta cũng có thể chọn nâng cấp lên latest, hoặc bất kỳ phiên bản nào sau v0.3.8).
Bước 9. Bây giờ hãy chạy lại govulncheck:
$ govulncheck ./...
Lần này bạn sẽ thấy kết quả sau:
govulncheck is an experimental tool. Share feedback at https://go.dev/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.
Cuối cùng, govulncheck xác nhận rằng không tìm thấy lỗ hổng nào.
Bằng cách thường xuyên quét các dependency của bạn bằng câu lệnh govulncheck, bạn có thể bảo vệ mã nguồn của mình thông qua việc phát hiện, sắp xếp ưu tiên và xử lý các lỗ hổng.