【发布时间】:2017-11-23 22:43:15
【问题描述】:
我正在使用 Golang 1.9.2 创建客户端应用程序,但无法访问我的后端。问题是我的应用程序在最新版本的 Windows 和 Linux 上运行良好,但是当我在 Windows XP 上运行它时(是的,不幸的是我必须支持 Windows XP,因为我们的一些客户拒绝升级他们的操作系统)我尝试执行 HTTP GET 和 HTTP POST 时出现此错误:x509: certificate signed by unknown authority。
我在 Windows XP 内部使用 Firefox ESR 浏览器和 Chromium 浏览器运行了相同的 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
}
是否有另一种方法可以解决此问题,而不必忽略证书验证?如果没有,我在代码中做错了什么?
【问题讨论】:
-
这很可能是因为系统的证书池严重过期,这是预料之中的,因为微软已经完全放弃了对 Windows XP 的支持。您需要手动将授权证书添加到系统证书池的副本中,并在它们过期或被替换时自动保持最新状态。您可以使用
pool, err := x509.SystemCertPool(),然后使用池的AddCert()函数来添加CA 的证书,最后在您的TLS 配置中使用该池来处理请求。 More info. -
您好,我尝试在 Windows 中手动安装证书(通过双击它们),但没有成功。接下来我会尝试你的建议。我只有一个问题:当我使用
AddCert()添加证书时,它们会被永久添加还是每次我的应用运行时都必须这样做? -
每次您的应用程序运行时。
x509.SystemCertPool()函数返回系统证书池的副本,对它的任何更改都只保存在内存中,不会写入磁盘。这就是为什么您需要设置一种安全的方式来在证书到期时自动更新证书。老实说,仅仅为了获得 Windows XP 支持就需要做很多工作。这就是网络浏览器所做的,它们保留自己的证书池,而忽略系统的证书池。 -
将证书添加到证书池的方法如下:stackoverflow.com/a/38825553/1696153
-
{InsecureSkipVerify : true}是一个黑客。前段时间我和你有同样的问题,虽然原因不同,但在几个地方发现这个跳过作为建议的解决方案。这不应该出现在生产代码中。