☰ Mục lục series
Tài liệu Go tiếng Việt
  1. Bắt đầu (Getting started)
    1. Tổng quan
    2. Tải về và cài đặt
    3. Bắt đầu với Go
    4. Quản lý các bản cài đặt Go
    5. Plugin trình soạn thảo và IDE
  2. Dạo quanh Go (A Tour of Go)
    1. Chào mừng
    2. Package, biến và hàm
    3. Điều khiển luồng
    4. Struct, slice và map
    5. Method và interface
    6. Generics
    7. Xử lý đồng thời
  3. Hướng dẫn (Tutorials)
    1. Danh sách hướng dẫn
    2. Tạo một Go module
    3. Gọi mã của bạn từ một module khác
    4. Trả về và xử lý lỗi
    5. Trả về lời chào ngẫu nhiên
    6. Trả về lời chào cho nhiều người
    7. Thêm một test
    8. Biên dịch và cài đặt ứng dụng
    9. Kết luận
    10. Bắt đầu với workspace nhiều module
    11. Phát triển RESTful API với Go và Gin
    12. Truy cập cơ sở dữ liệu quan hệ
    13. Bắt đầu với generics
    14. Bắt đầu với fuzzing
    15. Làm việc với JSON
    16. Tìm và sửa các dependency có lỗ hổng với govulncheck
    17. Tìm và khắc phục phụ thuộc có lỗ hổng với VS Code Go
    18. Viết ứng dụng web
  4. Viết code Go
    1. Cách viết mã Go
    2. Effective Go
    3. Doc Comment trong Go
  5. Module
    1. Phát triển và publish module
    2. Quản lý phụ thuộc
    3. Tổ chức một module Go
    4. Quản lý mã nguồn của module
    5. Cách đánh số phiên bản module
    6. Quy trình phát hành và đánh phiên bản module
    7. Publish một module
    8. Phát triển một bản cập nhật major version
    9. Tham chiếu tệp go.mod
    10. Ngừng hỗ trợ 'go get' cho việc cài đặt tệp thực thi
  6. Cơ sở dữ liệu (Database)
    1. Truy cập cơ sở dữ liệu quan hệ
    2. Mở một handle cơ sở dữ liệu
    3. Thực thi câu lệnh SQL không trả về dữ liệu
    4. Truy vấn dữ liệu
    5. Dùng prepared statement
    6. Thực thi transaction
    7. Huỷ các thao tác đang chạy
    8. Quản lý kết nối
    9. Tránh rủi ro SQL injection
  7. Chẩn đoán và hiệu năng
    1. Chẩn đoán
    2. Hướng dẫn về Go Garbage Collector
    3. Tối ưu hoá dựa trên profile
    4. Data Race Detector
    5. Gỡ lỗi mã Go bằng GDB
    6. Hỗ trợ coverage profiling cho integration test
  8. Bảo mật (Security)
    1. Tổng quan bảo mật
    2. Thực hành tốt về bảo mật cho lập trình viên Go
    3. Quản lý lỗ hổng trong Go
    4. Cơ sở dữ liệu lỗ hổng của Go
    5. Quét lỗ hổng trong IDE
    6. Chính sách CNA của Go
    7. Go Fuzzing
    8. Chi tiết kỹ thuật của Go Fuzzing
    9. Chính sách bảo mật của Go
    10. Threat Model của Go
    11. Các quyết định về bảo mật của Go
    12. Tuân thủ FIPS 140-3
  9. Công cụ và toolchain
    1. Tài liệu về các lệnh
    2. Về lệnh go
    3. Go Toolchains
    4. Telemetry của Go
    5. Cài đặt Go từ mã nguồn
    6. Cài đặt và sử dụng gccgo
  10. Tham khảo
    1. Câu hỏi thường gặp (FAQ)
    2. Go 1 và tương lai của các chương trình Go
    3. Hướng dẫn chuyển đổi sang encoding/json/v2
    4. Hướng dẫn đóng góp
    5. Đóng góp cho frontend gccgo
  11. Phụ lục
    1. Bảng thuật ngữ
Hướng dẫn (Tutorials)

Hướng dẫn: Tìm và sửa các dependency có lỗ hổng với govulncheck

Bản dịch từ go.dev/doc/tutorial/govulncheck

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:

  1. Tạo một module Go mẫu có một dependency chứa lỗ hổng
  2. Cài đặt và chạy govulncheck
  3. Đánh giá các lỗ hổng
  4. 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.

Nội dung gốc: Go Documentation © The Go Authors, giấy phép CC BY 3.0. Bản dịch và ghi chú: Lê Văn Dũng.