在http.NewRequest中检查服务器SSL/TLS证书的指纹。

huangapple go评论73阅读模式
英文:

Check fingerprints of server SSL/TLS certificates in http.NewRequest

问题

在Golang中,你可以使用crypto/x509crypto/sha1包来检查服务器SSL/TLS证书的指纹。下面是一个示例代码:

package main

import (
	"crypto/sha1"
	"crypto/x509"
	"encoding/hex"
	"fmt"
	"net/http"
)

func main() {
	// 创建一个自定义的验证回调函数
	verifyCallback := func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
		// 获取证书链中的第一个证书
		certificate, err := x509.ParseCertificate(rawCerts[0])
		if err != nil {
			return err
		}

		// 计算证书的SHA1指纹
		sha1Hash := sha1.Sum(certificate.Raw)
		fingerprint := hex.EncodeToString(sha1Hash[:])

		// 检查指纹是否在有效指纹列表中
		validFingerprints := []string{"指纹1", "指纹2", "指纹3"} // 替换为你的有效指纹列表
		for _, validFingerprint := range validFingerprints {
			if fingerprint == validFingerprint {
				return nil // 验证通过
			}
		}

		return fmt.Errorf("证书指纹不匹配")
	}

	// 创建一个自定义的HTTP客户端
	client := &http.Client{
		Transport: &http.Transport{
			TLSClientConfig: &tls.Config{
				InsecureSkipVerify: false, // 开启证书验证
				VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
					return verifyCallback(rawCerts, verifiedChains)
				},
			},
		},
	}

	// 发送HTTP请求
	resp, err := client.Get("https://example.com")
	if err != nil {
		fmt.Println("请求失败:", err)
		return
	}
	defer resp.Body.Close()

	// 处理响应
	// ...
}

请注意,你需要将示例代码中的validFingerprints替换为你自己的有效指纹列表。另外,还可以根据需要进行其他自定义验证操作。

英文:

How can I check the fingerprints of the server SSL/TLS certificates during a http request in golang?

This ruby code shows what I want to do in Go:

  @verify_callback = proc do |preverify_ok, store_context|
if preverify_ok and store_context.error == 0
certificate = OpenSSL::X509::Certificate.new(store_context.chain[0])
fingerprint = Digest::SHA1.hexdigest(certificate.to_der).upcase.scan(/../).join(":")
$valid_fingerprints.include?(fingerprint)
else
false
end
end

答案1

得分: 5

通常,在Go语言中生成证书指纹的过程非常简单。如果你已经有一个存储在cert中的x509.Certificate结构体,你只需要执行以下操作:

sha1Fingerprint := sha1.Sum(cert.Raw)

在请求完成后,从HTTP响应结构体中获取证书也很容易(使用resp.TLS.PeerCertificates),但似乎这不是你所需要的。

如果你需要在TLS连接建立时访问服务器的证书,我认为你需要创建自己的http.Transport并为其提供一个自定义的DialTLS实现。然后,在配置http.Client进行出站请求时使用该传输。

在你的自定义DialTLS函数中,你可以访问连接状态信息,如服务器的证书链,并从那里执行SHA1指纹生成。

英文:

In general the process of generating a certificate fingerprint in Go is pretty simple. If you already have an x509.Certificate struct, stored in cert, all you need to do is

sha1Fingerprint := sha1.Sum(cert.Raw)

Getting certificates from an HTTP response struct after the request is complete is also pretty easy (use resp.TLS.PeerCertificates), but it doesn't seem like that's what you need.

If you need access to the server's certificate at TLS connection set up time, I think you'll need to create your own http.Transport and hand it a custom implementation of DialTLS. You'd then use that transport when configuring an http.Client to make your outbound requests.

Within your custom DialTLS func you'd have access to connection state information like the server's certificate chain, and you could perform the SHA1 fingerprint generation from there.

答案2

得分: 0

你可能不应该自己实现证书检查,而是让net/http根据你提供的有效CA进行检查。此外,通常直接使用指纹进行操作并不值得麻烦。

以下是设置要求客户端使用证书进行身份验证的HTTPS服务器的示例。客户端证书必须由CA签名,否则SSL/TLS握手将停止。

// 服务器的证书和密钥
cert, err := tls.LoadX509KeyPair("server.crt", "server.key")
if err != nil {
   panic(err)
}

// 加载CA证书
capool := x509.NewCertPool()
cacert, err := ioutil.ReadFile("ca.crt")
if err != nil {
   panic(err)
}
capool.AppendCertsFromPEM(cacert)

// 服务器配置
config := tls.Config{Certificates: []tls.Certificate{cert}, ClientCAs: capool, ClientAuth: tls.RequireAndVerifyClientCert}
config.NextProtos = []string{"http/1.1"}
config.Rand = rand.Reader // 严格来说不是必需的,应该是默认值

// TLS web服务器
myTLSWebServer := &http.Server{Addr: "myaddress", TLSConfig: &config, Handler: nil}

// ... 继续设置处理程序等
http.HandleFunc("/", myHandler)

// 绑定端口并启动服务器
conn, err := net.Listen("tcp", settings.ServiceAddress)
if err != nil {
   panic(err)
}
tlsListener := tls.NewListener(conn, &config)
myTLSWebServer.Serve(tlsListener)

阅读tls.Config的文档将向您展示,通过更改参数(ClientAuth、ClientCAs、Certificates、RootCAs),您可以轻松选择不同的证书检查模式。通常,错误将以error的形式返回。

如果您坚持要检查指纹,您可以从请求的TLS状态中检索TLS状态tls.ConnectionState。我认为您应该使用该结构中的Signature进行指纹识别。大致上,您可以使用以下代码:

func lol(r *http.Request) {
    tls := r.TLS
    if tls != nil {
       // 为简单起见,尝试第一个证书
       cert := tls.PeerCertificates[0]
       signature := cert.Signature
       // 对签名进行处理
    }
}
英文:

You probably shouldn't implement certificate checking yourself, but let the net/http do the checking based on the valid CAs you provide. Also, usually working directly with fingerprints isn't worth the trouble.

For example, this is how you set up a HTTPS server that requires clients to authenticate by using a certificate. The client certificate must be signed by the CA, or the SSL/TLS handshake stops.

    // Server's own certificate & key
cert, err := tls.LoadX509KeyPair("server.crt", "server.key")
if err != nil {
panic(err)
}
// Load the CA certificate(s)
capool := x509.NewCertPool()
cacert, err := ioutil.ReadFile("ca.crt")
if err != nil {
panic(err)
}
capool.AppendCertsFromPEM(cacert)
// Server configuration
config := tls.Config{Certificates: []tls.Certificate{cert}, ClientCAs: capool, ClientAuth: tls.RequireAndVerifyClientCert}
config.NextProtos = []string{"http/1.1"}
config.Rand = rand.Reader // Strictly not necessary, should be default
// TLS web server
myTLSWebServer := &http.Server{Addr: "myaddress", TLSConfig: &config, Handler: nil}
// .. proceed with setting handlers etc
http.HandleFunc("/", myHandler)
// Bind to port and start the server up
conn, err := net.Listen("tcp", settings.ServiceAddress)
if err != nil {
panic(err)
}
tlsListener := tls.NewListener(conn, &config)
myTLSWebServer.Serve(tlsListener)

Reading the documentation for tls.Config will show you that by changing the parameters (ClientAuth, ClientCAs, Certificates, RootCAs) you can easily select different modes for checking the certificates. You usually get failures returned in error.

If you really insist on checking fingerprints, you can retrieve the TLS status from Request TLS *tls.ConnectionState. I think you should probably use the Signature from that struct for fingerprinting.. Off the top of my head, something roughly along the lines of

func lol(r *http.Request) {
tls := r.TLS
if tls != nil {
// Try the first one for simplicity
cert := tls.PeerCertificates[0]
signature := cert.Signature
// Do something with the signature
}
}

should do the trick.

huangapple
  • 本文由 发表于 2014年11月19日 08:19:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/27006725.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定