首頁  >  文章  >  後端開發  >  為什麼我會遇到「連線失敗:x509:憑證依賴舊版公用名字段,使用 SAN 或暫時啟用與 GODEBUG=x509ignoreCN=0 相符的公用名稱」錯誤

為什麼我會遇到「連線失敗:x509:憑證依賴舊版公用名字段,使用 SAN 或暫時啟用與 GODEBUG=x509ignoreCN=0 相符的公用名稱」錯誤

Barbara Streisand
Barbara Streisand原創
2024-10-28 12:10:30609瀏覽

Why am I encountering the

錯誤:Go TLS 連線中的憑證欄位差異

嘗試使用Go 與MongoDB 伺服器建立TLS 連線時,您可能會遇到以下錯誤:

failed to connect: x509: certificate relies on legacy Common Name field, use SANs or temporarily enable Common Name matching with GODEBUG=x509ignoreCN=0

原因:

當伺服器的TLS 憑證依賴舊版通用名稱(CN) 欄位進行識別時,會發生此錯誤,但Go的運行時預設使用主題備用名稱(SAN) 進行TLS 連線。

解決方案:

解決此問題的主要方法有兩種:

1.利用伺服器憑證中的SAN:

  • 使用與用於連接到伺服器的主機名稱或IP 位址相符的SAN 重新產生伺服器憑證。
  • 這可以透過使用來實現OpenSSL 或第三方憑證授權單位等工具。

2.暫時停用CN 匹配:

如果無法立即重新產生伺服器證書,可以透過設定環境變數來暫時停用CN 匹配:

GODEBUG=x509ignoreCN=0

但這不是長期解決方案,只能用於臨時建立連線。

程式碼實作:

如果您選擇在 Go 程式碼中修正問題,請確保您載入的憑證包含與連線期間使用的主機名稱相符的 SAN。以下是您提供的程式碼片段的更新版本:

<code class="go">const CONFIG_DB_CA = "/etc/ca-files/new-mongo.ca.crt"

func main() {
    cer, err := tls.LoadX509KeyPair("/mongo-server.crt", "/mongo-server.key")
    if err != nil {
        log.Println(err)
        return
    }

    roots := x509.NewCertPool()
    ca, err := ioutil.ReadFile(CONFIG_DB_CA)
    if err != nil {
        fmt.Printf("Failed to read or open CA File: %s.\n", CONFIG_DB_CA)
        return
    }
    roots.AppendCertsFromPEM(ca)

    tlsConfig := &tls.Config{
        Certificates: []tls.Certificate{cer},
        RootCAs:      roots,
        VerifyPeerCertificate: func(rawCerts [][]*x509.Certificate) error {
            for _, certs := range rawCerts {
                for _, cert := range certs {
                    if len(cert.Subject.CommonName) > 0 {
                        continue
                    }
                    for _, dns := range cert.DNSNames {
                        if dns == "customhost" || dns == "customhost:port" {
                            return nil
                        }
                    }
                    return errors.New("certificate does not contain a SAN for the host")
                }
            }
            return errors.New("no valid certificate found")
        },
    }

    conn, err := tls.Dial("tcp", "customhost:port", tlsConfig)
    if err != nil {
        fmt.Printf("failed to connect: %v.\n", err)
        return
    }

    err = conn.VerifyHostname("customhost")
    if err != nil {
        panic("Hostname doesn't match with certificate: " + err.Error())
    }
    for i, cert := range conn.ConnectionState().PeerCertificates {
        prefix := fmt.Sprintf("CERT%d::", i+1)
        fmt.Printf("%sIssuer: %s\n", prefix, cert.Issuer)
        fmt.Printf("%sExpiry: %v\n", prefix, cert.NotAfter.Format(time.RFC850))
        fmt.Printf("%sDNSNames: %v\n\n", prefix, cert.DNSNames)
    }

    fmt.Printf("Success!")
}</code>

此更新的程式碼使用自訂的VerifyPeerCertificate函數來驗證憑證是否包含與主機名稱相符的CN或與主機名稱相符的SAN。如果找到合適的證書,連線就會成功。

以上是為什麼我會遇到「連線失敗:x509:憑證依賴舊版公用名字段,使用 SAN 或暫時啟用與 GODEBUG=x509ignoreCN=0 相符的公用名稱」錯誤的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn