Golang HTTP x509: 证书由未知机构签名错误

30

我正在使用Golang 1.9.2创建一个客户端应用程序,但我在访问后端时遇到了一些问题。我的应用程序在最新版本的Windows和Linux中运行良好,但是当我在Windows XP上运行它时(是的,不幸的是,我必须支持Windows XP,因为我们的一些客户拒绝升级操作系统),尝试执行HTTP GET和HTTP POST时会出现以下错误:x509:由未知机构签名的证书

我已经使用Firefox ESR浏览器和Chromium浏览器从Windows XP内部运行相同的GET命令,并且它们都没有抱怨证书。

请注意,我的证书有效并由受信任的机构签名。

我做了一些研究,发现有些人也遇到了同样的问题,并通过忽略TLS验证来解决这个问题,方法是:

import ("net/http"; "crypto/tls")

tr := &http.Transport{
    TLSClientConfig: &tls.Config{InsecureSkipVerify : true},
}
client := &http.Client{Transport: tr}
resp, err := client.Get("https://someurl:443/)
所以我将这段代码添加到我的程序中,但它仍然无法正常工作。
// NewAPIClient - creates a new API client
func NewAPIClient() Client {
    c := &APIClient{}

    tr := &http.Transport{
        TLSClientConfig: &tls.Config{InsecureSkyVerify: true},
    }
    c.client = &http.Client{Transport: tr}
    return c
}

// GetTasks - retrieves a list of tasks from the backend.
func (c *APIClient) GetTasks() ([]byte, error) {
    conf := config.GetInstance()
    url := fmt.Sprintf("%s/myurl", conf.GetConfig().APIUrl)

    req, err := http.NewRequest(http.MethodGet, url, nil)
    if err != nil {
        log.WithError(err).Errorf("Error creating HTTP request")
        return nil, err
    }

    // Add headers
    req.Header.Add("Authorization", conf.GetConfig().APIToken)
    req.Header.Add("Accept", "application/json")

    log.Info("Retrieving tasks from the API")
    resp, err := c.client.Do(req)
    if err != nil {
        log.WithError(err).Errorf("Error retrieving tasks from the backend")
        return nil, err
    }
    defer resp.Body.Close()

    if resp.StatusCode != 200 {
        errMsg := fmt.Sprintf("Received status: %s", resp.Status)
        err = errors.New(errMsg)
        log.WithError(err).Error("Error retrieving tasks from the backend")
        return nil, err
    }

    tasks, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        log.WithError(err).Error("Error reading tasks response body")
        return nil, err
    }

    log.Info("The tasks were successfully retrieved")

    return tasks, nil
}

有没有另一种方法可以解决这个问题,而不必忽略证书验证?如果没有,那么我的代码哪里做错了吗?


14
这很可能是因为系统的证书池已经严重过时,这是预期的,因为微软已经完全停止支持Windows XP。您需要手动将该机构的证书添加到系统证书池的副本中,并在它们过期或被替换时自动更新它们。您可以使用pool, err := x509.SystemCertPool(),然后使用池的AddCert()函数添加CA证书,最后在TLS配置中使用该池进行请求。【更多信息】(https://golang.org/pkg/crypto/x509/#SystemCertPool) - Svenskunganka
你好,我已尝试手动在Windows中安装证书(通过双击它们),但没有成功。接下来我将尝试您的建议。我只有一个问题:当我使用AddCert()添加证书时,它们会被永久添加还是每次我的应用程序运行时都需要重新添加? - Felipe
每次您的应用程序运行时,x509.SystemCertPool() 函数都会返回系统证书池的 副本,对其进行的任何更改仅在内存中保留,而不写入磁盘。这就是为什么您需要设置安全的方式来自动更新证书以防止过期。说实话,为了获得 Windows XP 支持,需要做很多工作。这就是 Web 浏览器所做的,它们保留自己的证书池,并忽略系统的证书池。 - Svenskunganka
2
这里是如何将证书添加到证书池的方法:https://dev59.com/w1kT5IYBdhLWcg3wStgf#38825553 - Katie
如果您正在使用Docker,请参考此答案 https://dev59.com/bqnka4cB1Zd3GeqPL0sW#60909235 - Shubham Chaudhary
4
"{InsecureSkipVerify : true}" 是一种黑客行为。我之前也遇到过类似的问题,尽管原因不同,但在几个地方都找到了这个跳过验证的建议解决方案。这在生产代码中是不可接受的。 - Tomasz Giba
2个回答

11

您正在进行以下操作:

// NewAPIClient - creates a new API client
func NewAPIClient() Client {
    c := &APIClient{}

    tr := &http.Transport{
        TLSClientConfig: &tls.Config{InsecureSkyVerify: true}, // <--- Problem
    }
    c.client = &http.Client{Transport: tr}
    return c
}

但是正确的拼写是InsecureSkipVerify,而不是InsecureSkyVerify

需要注意的是InsecureSkipVerify 控制着客户端验证服务器证书链和主机名的方式。如果 InsecureSkipVerify 为 true,crypto/tls 将接受服务器呈现的任何证书以及该证书中的任何主机名。在这种模式下,TLS 易受中间人攻击,除非使用自定义验证。只应在测试环境或与 VerifyConnection 或 VerifyPeerCertificate 结合使用时使用该选项。


3

Golang使用操作系统的证书存储。以下注释表明在Windows上,Go使用Windows存储,类似于Linux

// CertGetCertificateChain将遍历Windows的根存储以尝试构建已验证的证书链

此注释及其相关代码位于以下文件中:

https://golang.org/src/crypto/x509/root_windows.go

将服务器证书、中间CA证书和/或根CA证书添加到Windows XP证书存储中。您可以使用IBM发布的以下Windows XP说明: 步骤:
  1. 在Windows XP中,选择“开始>运行”以打开命令行。
  2. 在“运行”对话框中键入mmc并单击“确定”以运行Microsoft Management Console(MMC)。
  3. 从MMC中,选择“文件>添加/删除快捷方式”。
  4. 单击“添加”。
  5. 单击“证书”。
  6. 单击“我的用户帐户”。
  7. 单击“完成”。
  8. 在“添加独立快捷方式”对话框上单击“关闭”。
  9. 在“添加/删除快捷方式”对话框上单击“确定”。

参考: https://www.ibm.com/docs/en/b2b-integrator/5.2?topic=xp-install-root-certificate-in-windows

GlobalSign和Securely为Windows的更现代版本提供类似的说明,但上面的IBM链接专门针对Windows XP。下面的Securely文档还包括屏幕截图。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接