如何使用错误的证书执行HTTPS请求?

假设我想以编程方式获取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.Config结构!?

199835 次浏览

安全注意事项:禁用安全检查是危险的,应该避免

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

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)
}
}

如果您想使用HTTP包中的默认设置,那么您不需要创建新的传输和客户端对象,您可以更改为忽略证书验证,如下所示:

tr := http.DefaultTransport.(*http.Transport)
tr.TLSClientConfig.InsecureSkipVerify = true

正确方法(自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}

警告:仅用于测试/开发目的。如有任何其他情况,请自行承担风险!

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

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

特别是,如果您使用客户端证书并依赖它们进行身份验证,您基本上会有一个实际上不再登录的假登录。拒绝InsecureSkipVerify的代码,否则您将以一种艰难的方式了解它的错误所在!

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

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

对CN的支持被弃用了很长一段时间(自2000年以来,在RFC 2818),Chrome浏览器甚至不会再查看CN,所以今天你需要拥有作为主题备用名称的URL的DNS域。

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

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

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

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