如何使用错误的证书进行https请求?

时间:2012-08-25 12:57:47

标签: ssl https go

说我想以编程方式获取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 struct!?

6 个答案:

答案 0 :(得分:216)

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

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

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

答案 1 :(得分:12)

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

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

// Create new Transport that ignores self-signed SSL
httpClientWithSelfSignedTLS := &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},
}

警告:仅用于测试/开发目的。还有其他事情,请自担风险!

答案 2 :(得分:11)

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

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

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

答案 3 :(得分:10)

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

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

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

答案 4 :(得分:7)

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

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

答案 5 :(得分:0)

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

以前,这可以通过将域设置为证书的cn或将域设置为“使用者备用名称”来实现。

很长一段时间以来一直不支持cn(自RFC 2818起2000年),Chrome浏览器甚至不再使用cn,因此今天您需要将URL的 DNS域作为主题备用名称。

RFC 6125,如果存在用于DNS域的SAN,则禁止检查cn,但如果存在用于IP地址的SAN,则不进行检查。 RFC 6125还重复了cn 28,这已经在RFC 2818中说过了。不存在证书颁发机构浏览器论坛,该论坛与RFC 6125结合意味着从不检查cn的DNS域名。