176

说我想以https://golang.org编程方式获得。目前golang.org(ssl)有一个错误的证书颁发给*.appspot.com所以当我运行这个时:

package main

import (
    "log"
    "net/http"
)

func main() {
    _, err := http.Get("https://golang.org/")
    if err != nil {
        log.Fatal(err)
    }
}

我得到(如我所料)

Get https://golang.org/: certificate is valid for *.appspot.com, *.*.appspot.com, appspot.com, not golang.org

现在,我想自己信任这个证书(想象一个我可以验证指纹等的自我颁发的证书):我如何提出请求并验证/信任证书?

我可能需要使用 openssl 下载证书,将其加载到我的文件中并填写tls.Configstruct !?

4

6 回答 6

357

安全说明:禁用安全检查是危险的,应该避免

您可以对默认客户端的所有请求全局禁用安全检查:

package main

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

func main() {
    http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
    _, err := http.Get("https://golang.org/")
    if err != nil {
        fmt.Println(err)
    }
}

您可以禁用客户端的安全检查:

package main

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

func main() {
    tr := &http.Transport{
        TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
    }
    client := &http.Client{Transport: tr}
    _, err := client.Get("https://golang.org/")
    if err != nil {
        fmt.Println(err)
    }
}
于 2012-08-25T14:12:29.543 回答
39

正确的方式(从 Go 1.13 开始)(由下面的答案提供):

customTransport := http.DefaultTransport.(*http.Transport).Clone()
customTransport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
client := &http.Client{Transport: customTransport}

原答案:

这是一种在不丢失默认设置的情况下执行此操作的方法DefaultTransport,并且不需要根据用户评论的虚假请求。

defaultTransport := http.DefaultTransport.(*http.Transport)

// Create new Transport that ignores self-signed SSL
customTransport := &http.Transport{
  Proxy:                 defaultTransport.Proxy,
  DialContext:           defaultTransport.DialContext,
  MaxIdleConns:          defaultTransport.MaxIdleConns,
  IdleConnTimeout:       defaultTransport.IdleConnTimeout,
  ExpectContinueTimeout: defaultTransport.ExpectContinueTimeout,
  TLSHandshakeTimeout:   defaultTransport.TLSHandshakeTimeout,
  TLSClientConfig:       &tls.Config{InsecureSkipVerify: true},
}
client := &http.Client{Transport: customTransport}

更短的方式:

customTransport := &(*http.DefaultTransport.(*http.Transport)) // make shallow copy
customTransport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
client := &http.Client{Transport: customTransport}

警告:仅用于测试/开发目的。其他任何事情,风险自负!!!

于 2017-09-02T07:02:32.047 回答
27

所有这些答案都是错误的!不要InsecureSkipVerify用于处理与主机名不匹配的 CN。Go 开发人员不明智地坚持不禁用主机名检查(它具有合法用途 - 隧道、nat、共享集群证书等),同时还有一些看起来相似但实际上完全忽略证书检查的东西。您需要知道证书是有效的并由您信任的证书签名。但在常见情况下,您知道 CN 与您连接的主机名不匹配。对于那些,设置ServerNametls.Config. 如果tls.Config.ServerName== remoteServerCN,则证书检查将成功。这就是你想要的。 InsecureSkipVerify表示没有认证;中间人的时机已经成熟;违背了使用 TLS 的目的。

有一个合法用途InsecureSkipVerify:使用它连接到主机并获取其证书,然后立即断开连接。如果您将代码设置为 use InsecureSkipVerify,通常是因为您没有ServerName正确设置(它需要来自 env var 或其他东西 - 不要为这个要求感到腹痛......正确执行)。

特别是,如果您使用客户端证书并依赖它们进行身份验证,那么您基本上拥有一个实际上不再登录的虚假登录。拒绝这样做的代码InsecureSkipVerify,否则你会很难知道它有什么问题!

于 2017-11-08T01:12:20.657 回答
13

如果您想保持默认传输设置,正确的方法是现在(从 Go 1.13 开始):

customTransport := http.DefaultTransport.(*http.Transport).Clone()
customTransport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
client = &http.Client{Transport: customTransport}

Transport.Clone制作传输的深层副本。这样您就不必担心随着时间的Transport推移会丢失任何添加到结构中的新字段。

于 2020-01-14T17:15:58.340 回答
6

如果您想使用 http 包中的默认设置,因此您不需要创建新的 Transport 和 Client 对象,您可以更改为忽略证书验证,如下所示:

tr := http.DefaultTransport.(*http.Transport)
tr.TLSClientConfig.InsecureSkipVerify = true
于 2017-01-20T15:36:51.797 回答
1

通常,URL 的 DNS 域必须与证书的证书主题匹配。

在以前,这可以通过将域设置为证书的 cn 或将域设置为主题备用名称。

对 cn 的支持已被弃用很长时间(自 2000 年在RFC 2818中),Chrome 浏览器甚至不再查看 cn 所以今天您需要将 URL 的 DNS 域作为主题备用名称。

RFC 6125禁止检查 cn 如果存在用于 DNS 域的 SAN,但如果存在用于 IP 地址的 SAN 则不会。RFC 6125 还重复 cn 已被弃用,这在 RFC 2818 中已经说过。证书颁发机构浏览器论坛的出现与 RFC 6125 结合本质上意味着永远不会检查 cn 的 DNS 域名。

于 2018-11-26T22:31:26.217 回答