Golang中客户端TLS认证遇到的问题
Golang中客户端TLS认证遇到的问题 我的问题是,在客户端首次向服务器发送请求后,服务器要求客户端提供证书,但客户端在响应中没有返回证书。我也用NodeJS测试过证书是否正常,在NodeJS中是可以工作的。我在几个论坛上询问过这个问题,但没有人真正知道如何解决这个问题 😔
我的代码:
import (
"bytes"
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"log"
"net/http"
)
func main() {
xml := `
<Packet>
<Header>
<ID>1231232132132354234</ID>
</Header>
<Body>
<Item>
<Content>SMS</Content>
<Phone_no>+123123213</Phone_no>
<Content>test</Content>
<OriginAddress>Posiljatelj</OriginAddress>
</Item>
</Body>
</Packet>
`
// Load client cert
cert, err := tls.LoadX509KeyPair("../cert/certNEW.pem", "../cert/serverNEW.key")
if err != nil {
log.Fatal(err)
}
// Load CA cert
caCert, err := ioutil.ReadFile("../cert/cacerts.cer")
if err != nil {
log.Fatal(err)
}
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)
// Setup HTTPS client
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{cert},
RootCAs: caCertPool,
InsecureSkipVerify: true,
}
tlsConfig.BuildNameToCertificate()
transport := &http.Transport{TLSClientConfig: tlsConfig}
client := &http.Client{Transport: transport}
resp, err := client.Post("https://api.url", "text/xml", bytes.NewBuffer([]byte(xml)))
if err != nil {
fmt.Println(err)
}
contents, err := ioutil.ReadAll(resp.Body)
fmt.Printf("%s\n", string(contents))
}

更多关于Golang中客户端TLS认证遇到的问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html
我不需要在信任列表中包含根证书,因为根证书已经存在于信任列表中。但是,如果其他编程语言可以正常工作,那么这里应该也能正常工作。
那我就不是很确定了。你做的比我通常做的要多(设置CA池之类的),但除此之外看起来应该能正常工作。从你的文件名来看,密钥可能与证书不匹配,但如果是这种情况,它应该无法加载。
是的,我尝试过这个方法,如果密钥和公钥不匹配,Go 程序在启动时就会报错。
但我认为证书本身应该是没问题的,因为在 NodeJs 中使用相同的证书是可以正常工作的。
我猜测可以重写该函数并从中返回你的证书。如果这个方法可行,但当证书不满足约束条件时,我就不知道该如何处理了。
calmh:
onfig.BuildNameToCertificate.
你好 @calmh
我已经尝试过这个方法了,很抱歉没有在问题中说明这一点
//tlsConfig.BuildNameToCertificate()
但结果还是一样的 🙁
当你在邮件列表中提问时,我给出了这个建议:
尝试不使用 Config.BuildNameToCertificate。
你没有说明是否尝试过。使用该方法会使 TLS 包根据证书的通用名称来响应证书请求。在客户端场景中,这很可能无法满足你的需求。很可能你只是想发送列表中的第一个证书。
func main() {
fmt.Println("hello world")
}
hey。
能否请教你关于如何使用 tls.Config.GetClientCertificate 的问题?它在 TLS 配置中定义为 GetClientCertificate func(*CertificateRequestInfo) (*Certificate, error)。
我在 Git 上得到了很好的反馈,但不知道该如何定义这个😊: “我认为这里的情况是证书请求施加了某些限制(RSA 与 ECDSA,或特定颁发机构),而你的证书未能满足这些要求。”
“你可以通过使用 tls.Config.GetClientCertificate 来绕过默认逻辑”
在Go中实现客户端TLS证书认证时,常见问题是证书配置不正确或TLS握手参数缺失。以下是针对您代码的修改方案:
import (
"bytes"
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"log"
"net/http"
)
func main() {
xml := `
<Packet>
<Header>
<ID>1231232132132354234</ID>
</Header>
<Body>
<Item>
<Content>SMS</Content>
<Phone_no>+123123213</Phone_no>
<Content>test</Content>
<OriginAddress>Posiljatelj</OriginAddress>
</Item>
</Body>
</Packet>
`
// 加载客户端证书
cert, err := tls.LoadX509KeyPair("../cert/certNEW.pem", "../cert/serverNEW.key")
if err != nil {
log.Fatal("加载客户端证书失败:", err)
}
// 加载CA证书
caCert, err := ioutil.ReadFile("../cert/cacerts.cer")
if err != nil {
log.Fatal("加载CA证书失败:", err)
}
caCertPool := x509.NewCertPool()
if !caCertPool.AppendCertsFromPEM(caCert) {
log.Fatal("无法解析CA证书")
}
// 配置TLS
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{cert},
RootCAs: caCertPool,
// 关键:明确设置客户端认证
ServerName: "api.url", // 替换为实际服务器域名
}
transport := &http.Transport{
TLSClientConfig: tlsConfig,
// 可选:启用连接复用
MaxIdleConns: 10,
}
client := &http.Client{
Transport: transport,
Timeout: 30 * time.Second, // 添加超时控制
}
resp, err := client.Post("https://api.url", "text/xml", bytes.NewBuffer([]byte(xml)))
if err != nil {
log.Fatal("请求失败:", err)
}
defer resp.Body.Close()
contents, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal("读取响应失败:", err)
}
fmt.Printf("响应状态: %d\n", resp.StatusCode)
fmt.Printf("响应内容: %s\n", string(contents))
}
主要修改点:
- 移除了
InsecureSkipVerify: true,这会跳过服务器证书验证 - 添加了
ServerName字段,用于TLS握手时的服务器名称指示 - 增加了证书加载的错误检查
- 添加了响应处理和资源清理
如果问题仍然存在,可以添加TLS调试信息:
import "crypto/tls"
// 在tlsConfig中添加
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{cert},
RootCAs: caCertPool,
ServerName: "api.url",
}
// 启用TLS调试(需要设置环境变量)
// GODEBUG=x509ignoreCN=0,x509sha1=1 go run yourprogram.go
证书文件路径需要确保正确,且证书格式应为PEM格式。如果使用DER格式的CA证书,需要使用x509.ParseCertificate代替AppendCertsFromPEM。


