Fiber的app.ListenTLS不支持双向认证,必须用app.Listener配合自定义http.Server并设置TLSConfig.ClientAuth为RequireAndVerifyClientCert及加载ClientCAs。

fiber.ListenTLS 不支持双向认证,必须用 app.Listener + 自定义 http.Server
Fiber 的 app.ListenTLS 只处理单向 TLS(服务器证书),它底层调用 tls.Listen 时固定设为 ClientAuth: tls.NoClientCert,没有暴露配置入口。想启用双向认证(mTLS),你得绕过 ListenTLS,改用 app.Listener 获取底层 listener,再手动构造 http.Server 并设置 TLSConfig。
常见错误写法:app.ListenTLS(":443", "fullchain.pem", "key.pem") —— 这永远无法触发客户端证书校验,即使你后续在路由里读 c.Get("X-SSL-Client-Cert") 也拿不到。
正确路径是:创建 tls.Config → 设置 ClientAuth: tls.RequireAndVerifyClientCert → 加载 CA 根证书到 ClientCAs → 传给 http.Server.TLSConfig。
如何加载客户端 CA 证书并强制校验
双向认证的关键不是“让客户端发证书”,而是“服务器必须验证它”。这依赖两个动作:把可信的 CA 根证书(比如 ca.crt)加载进 TLSConfig.ClientCAs,并把 ClientAuth 设为严格模式。
注意点:
-
ClientCAs必须是 *x509.CertPool 类型,不能直接传文件路径;要用io/ioutil.ReadFile(Go 1.16+ 推荐os.ReadFile)读取ca.crt内容,再用x509.NewCertPool()和AppendCertsFromPEM()加载 - 如果
ca.crt实际是 PEM 格式但含 Windows CRLF 换行符,AppendCertsFromPEM会静默失败,ClientCAs为空,导致所有客户端连接被拒绝(报tls: bad certificate) -
TLSConfig.RootCAs是给客户端用的(验证服务器证书),和ClientCAs完全无关,别混淆
示例关键片段:
cert, err := tls.LoadX509KeyPair("fullchain.pem", "key.pem")
if err != nil {
log.Fatal(err)
}
caCert, _ := os.ReadFile("ca.crt")
caPool := x509.NewCertPool()
caPool.AppendCertsFromPEM(caCert)
srv := &http.Server{
Addr: ":443",
Handler: app,
TLSConfig: &tls.Config{
Certificates: []tls.Certificate{cert},
ClientAuth: tls.RequireAndVerifyClientCert,
ClientCAs: caPool,
},
}
log.Fatal(srv.ListenAndServeTLS("", ""))
客户端证书没被识别?检查三个硬性条件
即使服务端配置正确,客户端证书仍可能被拒,原因往往卡在这三点:
- 客户端证书的
Extended Key Usage必须包含clientAuth(OID1.3.6.1.5.5.7.3.2)。OpenSSL 默认生成的自签名证书不带这个扩展,需显式加:openssl req -new -key client.key -out client.csr -addext "extendedKeyUsage=clientAuth" - 客户端证书链必须完整可验证:从客户端证书 → 中间 CA → 根 CA,每级签名都要能回溯。若中间 CA 缺失,
tls: certificate signed by unknown authority错误会出现,且发生在服务器日志里,不是浏览器提示 - 客户端发起连接时,必须主动提供证书。比如用 curl 测试,得加
--cert client.crt --key client.key;Node.js 的tls.connect需传cert和key选项;浏览器访问则需提前将client.p12导入系统或浏览器证书管理器
为什么 Fiber v3 的 Config 里没有 mTLS 开关
因为 mTLS 不是 HTTP 层协议特性,而是 TLS 握手阶段的行为,必须由 http.Server.TLSConfig 控制。Fiber 的 Config 结构体只管路由、中间件、编码器等应用层行为,不侵入传输层细节——这是有意为之的设计边界。
这也意味着:你无法靠修改 fiber.Config 字段开启双向认证;任何试图在 app.Use 中拦截并“手动校验证书”的做法都是错的,因为客户端证书在 TLS 握手完成前根本不会到达 HTTP 层。
真正生效的只有那一个 http.Server.TLSConfig.ClientAuth 值,以及它所依赖的 ClientCAs 内容是否有效。其他所有“中间件校验”都只是补救措施,无法替代 TLS 层的强制约束。


















