Golang中如何实现客户端的TLS认证

Golang中如何实现客户端的TLS认证 是否有办法使用TLS对浏览器进行身份验证?

我开发的软件提供了一个Web界面,我希望将访问权限仅限于受信任的客户端(浏览器)。所谓"受信任",指的是那些已手动安装了正确"证书"文件的客户端。

换句话说,我想知道是否能够生成特殊的证书+密钥文件(用于http.ListenAndServeTLS函数),同时生成一个额外的"密钥"文件供客户端浏览器导入到证书存储中。这一切都是为了确保只有导入了此"密钥"文件的浏览器才能访问Web界面。

我不关心服务器信任问题——只关心客户端信任。

5 回复

谢谢——这非常有帮助。

唯一剩下的问题是:如何创建客户端证书?

更多关于Golang中如何实现客户端的TLS认证的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


主要方法是通过命令行工具:https://gist.github.com/mtigas/952344 包含关于生成证书的CLI教程

当我初次看到您的问题时,关于认证的适用性涌现了许多想法困扰着我,于是我深入探究了为何有人会这样做。关于使用证书的原因我找到了一些很好的解答,这里提供一些让服务器要求客户端证书的帮助信息:https://stackoverflow.com/questions/24181081/request-client-certificate-for-authentication

如需了解Go标准库中TLS相关设置的更多详细信息,请参考:https://godoc.org/crypto/tls#Config

感谢您的问题,让我有机会学到了本不会想到要了解的知识。

谢谢!

供参考,为了让代码正常工作,我需要在 “server.TLSConfig.ClientCAs” 中添加 “ca.crt”

func start_ssl_server() {
	fi, _ := os.Stat("ca.key")
	if fi == nil || fi.Size() < 100 {
		println("ca.key not found")
		return
	}

	// try to start SSL server...
	dat, err := ioutil.ReadFile("ca.crt")
	if err != nil {
		println("ca.crt not found")
		// no "ca.crt" file - do not start SSL server
		return
	}

	server := &http.Server{
		Addr: ":4433",
		TLSConfig: &tls.Config{
			ClientAuth: tls.RequireAndVerifyClientCert,
		},
	}
	server.TLSConfig.ClientCAs = x509.NewCertPool()
	ok := server.TLSConfig.ClientCAs.AppendCertsFromPEM(dat)
	if !ok {
		println("AppendCertsFromPEM error")
		return
	}

	println("Starting SSL server at port 4433...")
	err = server.ListenAndServeTLS("ca.crt", "ca.key")
	if err != nil {
		println(err.Error())
	}
}

在Golang中实现客户端TLS认证(双向TLS认证)是可行的,这要求客户端提供证书来验证其身份。以下是完整的实现方案:

1. 生成证书和密钥文件

首先,需要生成CA证书、服务器证书和客户端证书:

# 生成CA私钥和证书
openssl genrsa -out ca.key 2048
openssl req -new -x509 -days 365 -key ca.key -out ca.crt -subj "/CN=My CA"

# 生成服务器私钥和证书
openssl genrsa -out server.key 2048
openssl req -new -key server.key -out server.csr -subj "/CN=localhost"
openssl x509 -req -days 365 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt

# 生成客户端私钥和证书
openssl genrsa -out client.key 2048
openssl req -new -key client.key -out client.csr -subj "/CN=My Client"
openssl x509 -req -days 365 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 02 -out client.crt

# 将客户端证书和私钥合并为PKCS#12格式(供浏览器导入)
openssl pkcs12 -export -out client.p12 -inkey client.key -in client.crt -certfile ca.crt

2. Go服务器端实现

package main

import (
    "crypto/tls"
    "crypto/x509"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
)

func main() {
    // 加载CA证书用于验证客户端
    caCert, err := ioutil.ReadFile("ca.crt")
    if err != nil {
        log.Fatal(err)
    }
    
    caCertPool := x509.NewCertPool()
    caCertPool.AppendCertsFromPEM(caCert)

    // 配置TLS
    tlsConfig := &tls.Config{
        ClientCAs: caCertPool,
        ClientAuth: tls.RequireAndVerifyClientCert,
        MinVersion: tls.VersionTLS12,
    }

    // 创建HTTP服务器
    mux := http.NewServeMux()
    mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        if len(r.TLS.PeerCertificates) > 0 {
            fmt.Fprintf(w, "Hello, authenticated client! Certificate Subject: %s", 
                r.TLS.PeerCertificates[0].Subject)
        } else {
            fmt.Fprintf(w, "No client certificate provided")
        }
    })

    server := &http.Server{
        Addr:      ":8443",
        Handler:   mux,
        TLSConfig: tlsConfig,
    }

    log.Println("Server starting on :8443")
    log.Fatal(server.ListenAndServeTLS("server.crt", "server.key"))
}

3. 客户端配置说明

用户需要将生成的 client.p12 文件导入到浏览器中:

  • Chrome/Edge: 设置 → 隐私和安全性 → 安全 → 管理证书 → 导入
  • Firefox: 选项 → 隐私与安全 → 证书 → 查看证书 → 您的证书 → 导入

4. 测试验证

启动服务器后,使用导入了客户端证书的浏览器访问 https://localhost:8443。服务器将验证客户端证书的有效性,只有提供有效证书的客户端才能成功访问。

这种实现确保了只有安装了指定客户端证书的浏览器才能访问你的Web界面,实现了基于客户端证书的身份验证机制。

回到顶部