数据库网站建设软件芷江建设局的工作人员网站
- 作者: 五速梦信息网
- 时间: 2026年04月20日 08:26
当前位置: 首页 > news >正文
数据库网站建设软件,芷江建设局的工作人员网站,杭州制作网页与网站,一个做网站的团队需要哪些人员随着互联网的发展#xff0c;网站提供的服务类型和规模不断扩大#xff0c;同时也对Web服务的安全性提出了更高的要求。TLS(Transport Layer Security)[1]已然成为Web服务最重要的安全基础设施之一。默认情况下#xff0c;一个TLS服务器通常只绑定一个证书[2]#xff0c;但… 随着互联网的发展网站提供的服务类型和规模不断扩大同时也对Web服务的安全性提出了更高的要求。TLS(Transport Layer Security)[1]已然成为Web服务最重要的安全基础设施之一。默认情况下一个TLS服务器通常只绑定一个证书[2]但当服务复杂度增加时单一证书已然难以满足需求。这时服务端绑定多个TLS证书就成为一个非常实用的功能。 Go语言中的net/http包和tls包对TLS提供了强大的支持在密码学和安全专家Filippo Valsorda[3]的精心设计下Go提供了多种TLS服务端绑定证书的方式本文将详细探讨服务端绑定TLS证书的几种方式包括绑定单个证书、多个证书、自定义证书绑定逻辑等。我会配合示例代码了解每种方式的使用场景、实现原理和优缺点。 注本文假设读者已熟悉基本的TLS使用方法[4]并具备Go语言编程经验。如果你不具备Go语言基础知识可以将学习我撰写的极客时间专栏《Go语言第一课》[5]作为你入门Go的起点。 1. 热身制作证书 为了后续示例说明方便我们先来把示例所需的私钥和证书都做出来本文涉及的证书以及他们之间的签发关系如下图 注示例使用的自签名根证书。 从图中我们看到我们证书分为三个层次最左边是CA的根证书(root certificate比如ca-cert.pem)之后是根CA签发的中间CA证书(intermediate certificate比如inter-cert.pem)从安全和管理角度出发真正签发服务器证书的都是这些中间CA最右侧则是由中间CA签发的叶子证书(leaf certificate比如leaf-server-cert.pem)也就是服务器配置的服务端证书(server certificate)我们为三个不同域名创建了不同的服务器证书。 在这里我们制作上述证书没有使用类似openssl[6]这样的工具而是通过Go代码生成的下面是生成上述证书的代码片段 // tls-certs-binding/make_certs/main.gofunc main() {// 生成CA根证书密钥对caKey, err : rsa.GenerateKey(rand.Reader, 2048)checkError(err)// 生成CA证书模板caTemplate : x509.Certificate{SerialNumber: big.NewInt(1),Subject: pkix.Name{Organization: []string{Go CA},},NotBefore: time.Now(),NotAfter: time.Now().Add(time.Hour * 24 * 365),KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,BasicConstraintsValid: true,IsCA: true,}// 使用模板自签名生成CA证书caCert, err : x509.CreateCertificate(rand.Reader, caTemplate, caTemplate, caKey.PublicKey, caKey)checkError(err)// 生成中间CA密钥对interKey, err : rsa.GenerateKey(rand.Reader, 2048)checkError(err)// 生成中间CA证书模板interTemplate : x509.Certificate{SerialNumber: big.NewInt(2),Subject: pkix.Name{Organization: []string{Go Intermediate CA},},NotBefore: time.Now(),NotAfter: time.Now().Add(time.Hour * 24 * 365),KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,BasicConstraintsValid: true,IsCA: true,}// 用CA证书签名生成中间CA证书interCert, err : x509.CreateCertificate(rand.Reader, interTemplate, caTemplate, interKey.PublicKey, caKey)checkError(err)// 生成叶子证书密钥对leafKey, err : rsa.GenerateKey(rand.Reader, 2048)checkError(err)// 生成叶子证书模板,CN为server.comleafTemplate : x509.Certificate{SerialNumber: big.NewInt(3),Subject: pkix.Name{Organization: []string{Go Server},CommonName: server.com,},NotBefore: time.Now(),NotAfter: time.Now().Add(time.Hour * 24 * 365),KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},IPAddresses: []net.IP{net.ParseIP(127.0.0.1)},DNSNames: []string{server.com},SubjectKeyId: []byte{1, 2, 3, 4},}// 用中间CA证书签名生成叶子证书leafCert, err : x509.CreateCertificate(rand.Reader, leafTemplate, interTemplate, leafKey.PublicKey, interKey)checkError(err)// 生成server1.com叶子证书leafKey1, _ : rsa.GenerateKey(rand.Reader, 2048)leafTemplate1 : x509.Certificate{SerialNumber: big.NewInt(4),Subject: pkix.Name{CommonName: server1.com,},NotBefore: time.Now(),NotAfter: time.Now().Add(time.Hour * 24 * 365),KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},DNSNames: []string{server1.com},}leafCert1, _ : x509.CreateCertificate(rand.Reader, leafTemplate1, interTemplate, leafKey1.PublicKey, interKey)// 生成server2.com叶子证书leafKey2, _ : rsa.GenerateKey(rand.Reader, 2048)leafTemplate2 : x509.Certificate{SerialNumber: big.NewInt(5),Subject: pkix.Name{CommonName: server2.com,},NotBefore: time.Now(),NotAfter: time.Now().Add(time.Hour * 24 * 365),KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},DNSNames: []string{server2.com},}leafCert2, _ : x509.CreateCertificate(rand.Reader, leafTemplate2, interTemplate, leafKey2.PublicKey, interKey)// 将证书和密钥编码为PEM格式caCertPEM : pem.EncodeToMemory(pem.Block{Type: CERTIFICATE, Bytes: caCert})caKeyPEM : pem.EncodeToMemory(pem.Block{Type: RSA PRIVATE KEY, Bytes: x509.MarshalPKCS1PrivateKey(caKey)})interCertPEM : pem.EncodeToMemory(pem.Block{Type: CERTIFICATE, Bytes: interCert})interKeyPEM : pem.EncodeToMemory(pem.Block{Type: RSA PRIVATE KEY, Bytes: x509.MarshalPKCS1PrivateKey(interKey)})leafCertPEM : pem.EncodeToMemory(pem.Block{Type: CERTIFICATE, Bytes: leafCert})leafKeyPEM : pem.EncodeToMemory(pem.Block{Type: RSA PRIVATE KEY, Bytes: x509.MarshalPKCS1PrivateKey(leafKey)})leafCertPEM1 : pem.EncodeToMemory(pem.Block{Type: CERTIFICATE, Bytes: leafCert1})leafKeyPEM1 : pem.EncodeToMemory(pem.Block{Type: RSA PRIVATE KEY, Bytes: x509.MarshalPKCS1PrivateKey(leafKey1)})leafCertPEM2 : pem.EncodeToMemory(pem.Block{Type: CERTIFICATE, Bytes: leafCert2})leafKeyPEM2 : pem.EncodeToMemory(pem.Block{Type: RSA PRIVATE KEY, Bytes: x509.MarshalPKCS1PrivateKey(leafKey2)})// 将PEM写入文件writeDataToFile(ca-cert.pem, caCertPEM)writeDataToFile(ca-key.pem, caKeyPEM)writeDataToFile(inter-cert.pem, interCertPEM)writeDataToFile(inter-key.pem, interKeyPEM)writeDataToFile(leaf-server-cert.pem, leafCertPEM)writeDataToFile(leaf-server-key.pem, leafKeyPEM)writeDataToFile(leaf-server1-cert.pem, leafCertPEM1)writeDataToFile(leaf-server1-key.pem, leafKeyPEM1)writeDataToFile(leaf-server2-cert.pem, leafCertPEM2)writeDataToFile(leaf-server2-key.pem, leafKeyPEM2) } 运行这个程序后当前目录下就会出现如下私钥文件(xx-key.pem)和证书文件(xx-cert.pem) \(ls *pem ca-cert.pem inter-cert.pem leaf-server-cert.pem leaf-server1-cert.pem leaf-server2-cert.pem ca-key.pem inter-key.pem leaf-server-key.pem leaf-server1-key.pem leaf-server2-key.pem 制作完证书后我们就来看看日常使用最多的绑定单一TLS证书的情况。 2. 绑定单一TLS证书 做过web应用的读者想必对绑定单一TLS证书的实现方式并不陌生。服务端只需要加载一对服务端私钥与公钥证书即可对外提供基于TLS的安全网络服务这里一个echo服务为例我们来看下服务端的代码 // tls-certs-binding/bind_single_cert/sever/main.go// 服务端 func startServer(certFile, keyFile string) {// 读取证书和密钥cert, err : tls.LoadX509KeyPair(certFile, keyFile)if err ! nil {log.Fatal(err)}// 创建TLS配置config : tls.Config{Certificates: []tls.Certificate{cert},}// 启动TLS服务器listener, err : tls.Listen(tcp, :8443, config)if err ! nil {log.Fatal(err)}defer listener.Close()log.Println(Server started)for {conn, err : listener.Accept()if err ! nil {log.Println(err)continue}handleConnection(conn)} }func handleConnection(conn net.Conn) {defer conn.Close()// 处理连接...// 循环读取客户端的数据for {buf : make([]byte, 1024)n, err : conn.Read(buf)if err ! nil {// 读取失败则退出return}// 回显数据给客户端s : string(buf[:n])fmt.Printf(recv data: %s\n, s)conn.Write(buf[:n])} }func main() {// 启动服务器startServer(leaf-server-cert.pem, leaf-server-key.pem) } 根据TLS的原理客户端在与服务端的握手过程中服务端会将服务端证书(leaf-server-cert.pem)发到客户端供后者验证客户端使用服务器公钥证书校验服务器身份。这一过程的实质是客户端利用CA证书中的公钥或中间CA证书中的公钥对服务端证书中由CA私钥或中间CA私钥签名的数据进行验签。 // tls-certs-binding/bind_single_cert/client/main.gofunc main() {caCert, err : ioutil.ReadFile(inter-cert.pem)if err ! nil {log.Fatal(err)}caCertPool : x509.NewCertPool()caCertPool.AppendCertsFromPEM(caCert)config : tls.Config{RootCAs: caCertPool,}conn, err : tls.Dial(tcp, server.com:8443, config)if err ! nil {log.Fatal(err)}defer conn.Close()// 每秒发送信息ticker : time.NewTicker(time.Second)for range ticker.C {msg : hello, tlsconn.Write([]byte(msg))// 读取回复buf : make([]byte, len(msg))conn.Read(buf)log.Println(string(buf))}} 这里我们使用了签发了leaf-server-cert.pem证书的中间CA(inter-cert.pem)来验证服务端证书(leaf-server-cert.pem)的合法性毫无疑问这是会成功的 // server \)go run main.go 2023/10/05 22:49:17 Server started// client\(go run main.go 2023/10/05 22:49:22 hello, tls 2023/10/05 22:49:23 hello, tls ... ... 注运行上述代码之前需修改/etc/hosts文件添加server.com的IP为127.0.0.1。 不过要注意的是在这里用CA根证书(ca-cert.pem)直接验证叶子证书(leaf-server-cert.pem)会失败因为根证书不是叶子证书的直接签发者必须通过验证证书链来建立根证书和叶子证书之间的信任链。 3. 证书链 实际生产中服务器实体证书和根证书分别只有一张但中间证书可以有多张这些中间证书在客户端并不一定存在这就可能导致客户端与服务端的连接无法建立。通过openssl命令也可以印证这一点 // 在make_certs目录下// CA根证书无法直接验证叶子证书 \)openssl verify -CAfile ca-cert.pem leaf-server-cert.pem leaf-server-cert.pem: O Go Server, CN server.com error 20 at 0 depth lookup:unable to get local issuer certificate// 证书链不完整也无法验证 \(openssl verify -CAfile inter-cert.pem leaf-server-cert.pem leaf-server-cert.pem: O Go Intermediate CA error 2 at 1 depth lookup:unable to get issuer certificate// 需要用完整证书链来验证 \)openssl verify -CAfile ca-cert.pem -untrusted inter-cert.pem leaf-server-cert.pem leaf-server-cert.pem: OK 为此在建连阶段服务端不仅要将服务器实体证书发给客户端还要发送完整的证书链(如下图所示)。 证书链的最顶端是CA根证书它的签名值是自己签名的验证签名的公钥就包含在根证书中根证书的签发者Issuer与使用者Subject是相同的。除了根证书每个证书的签发者Issuer是它的上一级证书的使用者Subject。以上图为例下列关系是成立的 - ca-cert.pem的Issuer ca-cert.pem的Subject - inter1-cert.pem的Issuer ca-cert.pem的Subject - inter2-cert.pem的Issuer inter1-cert.pem的Subject … … - interN-cert.pem的Issuer interN-1-cert.pem的Subject - leaf-server-cert.pem的Issuer interN-cert.pem的Subject 每张证书包含的重要信息是签发者(Issuer)、数字签名算法、签名值、使用者Subject域名、使用者公钥。除了根证书每个证书比如inter2-cert.pem证书被它的上一级证书比如inter1-cert.pem证书对应的私钥签名签名值包含在证书中上一级证书包含的公钥可以用来验证该证书中的签名值(inter2-cert.pem证书可以用来验证inter1-cert.pem证书中的签名值)。 那么如何在服务端返回证书链呢如何在客户端接收并验证证书链呢我们来看下面示例。在这个示例中客户端仅部署了根证书(ca-cert.pem)而服务端需要将服务证书与签发服务证书的中间CA证书以证书链的形式返回给客户端。 我们先来看服务端 // tls-certs-binding/bind_single_cert/server-with-certs-chain/main.go// 服务端 func startServer(certFile, keyFile string) {// 读取证书和密钥cert, err : tls.LoadX509KeyPair(certFile, keyFile)if err ! nil {log.Fatal(err)}interCertBytes, err : os.ReadFile(inter-cert.pem)if err ! nil {log.Fatal(err)}interCertblock, _ : pem.Decode(interCertBytes)// 将中间证书添加到证书链cert.Certificate append(cert.Certificate, interCertblock.Bytes)// 创建TLS配置config : tls.Config{Certificates: []tls.Certificate{cert},}// 启动TLS服务器listener, err : tls.Listen(tcp, :8443, config)if err ! nil {log.Fatal(err)}defer listener.Close()log.Println(Server started)for {conn, err : listener.Accept()if err ! nil {log.Println(err)continue}handleConnection(conn)} } 我们看到服务端在加载完服务端证书后又将中间CA证书inter-cert.pem attach到cert.Certificate这样cert.Certificate中就构造出了一个证书链而不单单是一个服务端证书了。 我们要注意证书链构造时的顺序这里按照的是如下顺序构造证书链的 - 服务端证书 (leaf certificate) - 中间CA证书N - 中间CA证书N-1 … … - 中间CA证书2 - 中间CA证书1 如果客户端没有根CA证书 (root certificate)在服务端构造证书链时需要将根CA证书作为最后一个证书attach到证书链中。 下面则是客户端验证证书链的代码 // tls-certs-binding/bind_single_cert/client-verify-certs-chain/main.gofunc main() {// 加载ca-cert.pemcaCertBytes, err : os.ReadFile(ca-cert.pem)if err ! nil {log.Fatal(err)}caCertblock, : pem.Decode(caCertBytes)caCert, err : x509.ParseCertificate(caCertblock.Bytes)if err ! nil {log.Fatal(err)}// 创建TLS配置config : tls.Config{InsecureSkipVerify: true, // trigger to call VerifyPeerCertificate// 设置证书验证回调函数VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {// 解析服务端返回的证书链(顺序server-cert.pem, inter-cert.peminter-cert.pems issuer…)var issuer *x509.Certificatevar cert *x509.Certificatevar err errorif len(rawCerts) 0 {return errors.New(no server certificate found)}issuer caCertfor i : len(rawCerts) - 1; i 0; i– {cert, err x509.ParseCertificate(rawCerts[i])if err ! nil {return err}if !verifyCert(issuer, cert) {return errors.New(verifyCert failed)}issuer cert}return nil},}conn, err : tls.Dial(tcp, server.com:8443, config)if err ! nil {log.Fatal(err)}defer conn.Close()// 每秒发送信息ticker : time.NewTicker(time.Second)for range ticker.C {msg : hello, tlsconn.Write([]byte(msg))// 读取回复buf : make([]byte, len(msg))conn.Read(buf)log.Println(string(buf))}}// 验证cert是否是issuer的签发 func verifyCert(issuer, cert *x509.Certificate) bool {// 验证证书certPool : x509.NewCertPool()certPool.AddCert(issuer) // okopts : x509.VerifyOptions{Roots: certPool,}, err : cert.Verify(opts)return err nil } 从代码可以看到我们需要将InsecureSkipVerify设置为true才能触发证书链的自定义校验逻辑(VerifyPeerCertificate)。在VerifyPeerCertificate中我们先用ca根证书校验位于证书链最后的那个证书验证成功后用验证成功的证书验证倒数第二个证书依次类推知道全部证书都校验ok说明证书链是可信任的。 服务端绑定一个证书或一套证书链是最简单的也是最常见的方案但在一些场景下比如考虑支持多个域名、证书轮换等TLS服务端可能需要绑定多个证书以满足要求。下面我们就来看看如何为TLS服务端绑定多个证书。 4. 绑定多个TLS证书 这个示例的证书绑定情况如下图 我们在服务端部署并绑定了三个证书三个证书与域名的对应关系如下 - 证书leaf-server-cert.pem 对应 server.com - 证书leaf-server1-cert.pem 对应 server1.com - 证书leaf-server2-cert.pem 对应 server2.com 注在/etc/hosts中添加server1.com和server2.com对应的ip均为127.0.0.1。 // tls-certs-binding/bind_multi_certs/server/main.gofunc main() {certFiles : []string{leaf-server-cert.pem, leaf-server1-cert.pem, leaf-server2-cert.pem}keyFiles : []string{leaf-server-key.pem, leaf-server1-key.pem, leaf-server2-key.pem}// 启动服务器startServer(certFiles, keyFiles) }// 服务端 func startServer(certFiles, keyFiles []string) {// 读取证书和密钥var certs []tls.Certificatefor i : 0; i len(certFiles); i {cert, err : tls.LoadX509KeyPair(certFiles[i], keyFiles[i])if err ! nil {log.Fatal(err)}certs append(certs, cert)}// 创建TLS配置config : tls.Config{Certificates: certs,}// 启动TLS服务器listener, err : tls.Listen(tcp, :8443, config)if err ! nil {log.Fatal(err)}defer listener.Close()log.Println(Server started)for {conn, err : listener.Accept()if err ! nil {log.Println(err)continue}handleConnection(conn)} } 我们看到绑定多个证书与绑定一个证书的原理是完全一样的tls.Config的Certificates字段原本就是一个切片可以容纳单个证书也可以容纳证书链容纳多个证书也不是问题。 客户端代码变化不大我们仅是通过下面代码输出了服务端返回的证书的Subject.CN // tls-certs-binding/bind_multi_certs/client/main.go// 解析连接的服务器证书 certs : conn.ConnectionState().PeerCertificates if len(certs) 0 {log.Println(Server CN:, certs[0].Subject.CommonName) } 接下来我们通过client连接不同的域名得到如下执行结果 // 服务端 \(go run main.go 2023/10/06 10:22:38 Server started// 客户端 \)go run main.go -server server.com:8443 2023/10/06 10:22:57 Server CN: server.com 2023/10/06 10:22:58 hello, tls\(go run main.go -server server1.com:8443 2023/10/06 10:23:02 Server CN: server1.com 2023/10/06 10:23:03 hello, tls 2023/10/06 10:23:04 hello, tls\)go run main.go -server server2.com:8443 2023/10/06 10:23:08 Server CN: server2.com 2023/10/06 10:23:09 hello, tls … … 我们看到由于绑定多个域名对应的证书程序可以支持访问不同域名的请求并根据请求的域名返回对应域名的证书。 5. 自定义证书选择绑定逻辑 无论是单一TLS证书、证书链还是多TLS证书他们都有一个共同特点那就是证书的绑定是事先已知的是一种“静态”模式的绑定有些场景下服务端在初始化启动后并不会绑定某个固定的证书而是根据客户端的连接需求以及特定规则在证书池中选择某个匹配的证书。在这种情况下我们需要使用GetCertificate回调从自定义的证书池中选择匹配的证书而不能在用上面示例中那种“静态”模式了。 我们来看一个自定义证书选择逻辑的示例下面示意图展示了客户端和服务端的证书部署情况 我们主要看一下服务端的代码逻辑变动 // tls-certs-binding/bind_custom_logic/server/main.gofunc startServer(certsPath string) {// 创建TLS配置config : tls.Config{GetCertificate: func(info *tls.ClientHelloInfo) (*tls.Certificate, error) {// 根据clientHello信息选择certcertFile : fmt.Sprintf(%s/leaf-%s-cert.pem, certsPath, info.ServerName[:len(info.ServerName)-4])keyFile : fmt.Sprintf(%s/leaf-%s-key.pem, certsPath, info.ServerName[:len(info.ServerName)-4])// 读取证书和密钥cert, err : tls.LoadX509KeyPair(certFile, keyFile)return cert, err}, } … … } 我们看到: tls.Config我们建立了一个匿名函数赋值给了GetCertificate字段该函数的实现逻辑就是根据客户端clientHello信息(tls握手时发送的信息)按照规则从证书池目录中查找并加载对应的证书与其私钥信息。示例使用ServerName来查找带有同名信息的证书。 例子的运行结果与上面的示例都差不多这里就不赘述了。 利用这种动态的证书选择逻辑我们还可以实现通过执行外部命令来获取证书、从数据库加载证书等。 6. 小结 通过本文的介绍我们全面了解了在Go服务端绑定单个、多个TLS证书的各种方式。我们首先介绍了生成自签名证书的方法这为我们的示例程序奠定了基础。然后我们详细探讨了绑定单证书、证书链、多证书、定制从证书池取特定证书的逻辑等不同机制的用法、优劣势和适用场景。同时在介绍每种用法时我们都用代码示例进一步解释了这些绑定方式的具体实现流程。 单证书TLS简单易理解运行性能优异。多证书TLS在提高性能、安全性、便利管理等方面有着重要意义。而自定义证书选取逻辑则更加灵活。通过综合运用各种绑定机制可以使我们的Go语言服务器端更加强大和灵活。 本文示例所涉及的Go源码可以在这里[7]下载。 注代码仓库中的证书和key文件有效期为一年大家如发现证书已经过期可以在make_certs目录下重新生成各种证书和私钥并copy到对应的其他目录中去。 7. 参考资料 《深入浅出 HTTPS从原理到实战》[8] - https://book.douban.com/subject/30250772/Certificate chains and cross-certification[9] - https://en.wikipedia.org/wiki/X.509#Certificate_chains_and_cross-certification “Gopher部落”知识星球[10]旨在打造一个精品Go学习和进阶社群高品质首发Go技术文章“三天”首发阅读权每年两期Go语言发展现状分析每天提前1小时阅读到新鲜的Gopher日报网课、技术专栏、图书内容前瞻六小时内必答保证等满足你关于Go语言生态的所有需求2023年Gopher部落将进一步聚焦于如何编写雅、地道、可读、可测试的Go代码关注代码质量并深入理解Go核心技术并继续加强与星友的互动。欢迎大家加入 著名云主机服务厂商DigitalOcean发布最新的主机计划入门级Droplet配置升级为1 core CPU、1G内存、25G高速SSD价格5$/月。有使用DigitalOcean需求的朋友可以打开这个链接地址[11]https://m.do.co/c/bff6eed92687 开启你的DO主机之路。 Gopher Daily(Gopher每日新闻) - https://gopherdaily.tonybai.com 我的联系方式 微博(暂不可用)https://weibo.com/bigwhite20xx微博2https://weibo.com/u/6484441286博客tonybai.comgithub: https://github.com/bigwhiteGopher Daily归档 - https://github.com/bigwhite/gopherdaily 商务合作方式撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。 参考资料 [1] TLS(Transport Layer Security): https://tonybai.com/2023/01/13/go-and-tls13 [2] 一个TLS服务器通常只绑定一个证书: https://tonybai.com/2015/04/30/go-and-https [3] Filippo Valsorda: https://filippo.io/ [4] TLS使用方法: https://tonybai.com/2015/04/30/go-and-https [5] 《Go语言第一课》: http://gk.link/a/10AVZ [6] openssl: https://www.openssl.org [7] 这里: https://github.com/bigwhite/experiments/tree/master/tls-certs-binding [8] 《深入浅出 HTTPS从原理到实战》: https://book.douban.com/subject/30250772/ [9] Certificate chains and cross-certification: https://en.wikipedia.org/wiki/X.509#Certificate_chains_and_cross-certification [10] “Gopher部落”知识星球: https://public.zsxq.com/groups/51284458844544 [11] 链接地址: https://m.do.co/c/bff6eed92687
- 上一篇: 数据库课程设计报告网站开发抖音官网链接网站怎么做
- 下一篇: 数据库网站制作网站服务器安装教程视频
相关文章
-
数据库课程设计报告网站开发抖音官网链接网站怎么做
数据库课程设计报告网站开发抖音官网链接网站怎么做
- 技术栈
- 2026年04月20日
-
数据库跟网站内容产品关键词怎么找
数据库跟网站内容产品关键词怎么找
- 技术栈
- 2026年04月20日
-
数据库 网站开发所需流程wordpress 主题 百科
数据库 网站开发所需流程wordpress 主题 百科
- 技术栈
- 2026年04月20日
-
数据库网站制作网站服务器安装教程视频
数据库网站制作网站服务器安装教程视频
- 技术栈
- 2026年04月20日
-
数据库修改wordpress登录密码seo排名诊断
数据库修改wordpress登录密码seo排名诊断
- 技术栈
- 2026年04月20日
-
数码网站建设总体目标秦皇岛建设规划
数码网站建设总体目标秦皇岛建设规划
- 技术栈
- 2026年04月20日
