使用 Go 实现 TLS socket server

开发 后端
今天我们来了解一下如何创建一个通过 TLS 加密的 socket 服务。

 安全传输层协议 TLS,以前称为 SSL(Secure Sockets Layer) ,由于HTTPS的推出受到了很多人的欢迎。但是正如TLS的名称 Transport Layer Security 所示的那样,它实际上是独立于 HTTP,一个更深入的安全协议,我们可以将 TLS 视为 TCP 的安全版本,其提供了对 socket 通信进行加密和签名的功能。在我们的日常开发中,会将 gRPC 协议运行在TLS之上以确保安全。

[[406579]]

今天我们来了解一下如何创建一个通过 TLS 加密的 socket 服务。

1.TLS socket server

服务端示例 

  1. func main() {  
  2.   port :flag.String("port", "8360", "listening port")  
  3.   certFile :flag.String("cert", "cert.pem", "certificate PEM file")  
  4.   keyFile :flag.String("key", "key.pem", "key PEM file")  
  5.   flag.Parse()  
  6.   cert, err :tls.LoadX509KeyPair(*certFile, *keyFile)  
  7.   if err != nil {  
  8.     log.Fatal(err)  
  9.   }  
  10.   config := &tls.Config{Certificates: []tls.Certificate{cert}}  
  11.   log.Printf("listening on port %s\n", *port)  
  12.   l, err :tls.Listen("tcp", ":"+*port, config)  
  13.   if err != nil {  
  14.     log.Fatal(err)  
  15.   }  
  16.   defer l.Close()  
  17.   for {  
  18.     conn, err :l.Accept()  
  19.     if err != nil {  
  20.       log.Fatal(err)  
  21.     }  
  22.     log.Printf("accepted connection from %s\n", conn.RemoteAddr())  
  23.     go func(c net.Conn) {  
  24.       io.Copy(c, c)  
  25.       c.Close()  
  26.       log.Printf("closing connection from %s\n", conn.RemoteAddr())  
  27.     }(conn)  
  28.   }  

这个服务端程序接受来自多个客户端并发请求,并向客户端发送的所有的镜像数据。和非TLS服务相比,这里用 tls.Listen 替换了 net.Listen,同时需要提供一个可用的 tls.Config,我们可以使用 mkcert 命令来生成证书和密钥对文件。

2.TLS socket client

客户端示例: 

  1. func main() {  
  2.   port :flag.String("port", "8360", "port to connect")  
  3.   certFile :flag.String("certfile", "cert.pem", "trusted CA certificate") 
  4.   flag.Parse()  
  5.   cert, err :os.ReadFile(*certFile)  
  6.   if err != nil {  
  7.     log.Fatal(err)  
  8.   } 
  9.    certPool :x509.NewCertPool()  
  10.   if ok :certPool.AppendCertsFromPEM(cert); !ok {  
  11.     log.Fatalf("unable to parse cert from %s", *certFile)  
  12.   }  
  13.   config := &tls.Config{RootCAs: certPool}  
  14.   conn, err :tls.Dial("tcp", "localhost:"+*port, config)  
  15.   if err != nil {  
  16.     log.Fatal(err)  
  17.   }  
  18.   _, err = io.WriteString(conn, "Hello simple secure Server\n")  
  19.   if err != nil {  
  20.     log.Fatal("client write error:", err)  
  21.   }  
  22.   if err = conn.CloseWrite(); err != nil {  
  23.     log.Fatal(err)  
  24.   }  
  25.   buf :make([]byte, 256)  
  26.   n, err :conn.Read(buf)  
  27.   if err != nil && err != io.EOF {  
  28.     log.Fatal(err)  
  29.   }  
  30.   fmt.Println("client read:", string(buf[:n]))  
  31.   conn.Close()  

和非 TLS 客户端相比,我们同样也只是把 net.Dial 换成 tls.Dial, tls.Config 中填写的证书可以选择权威 ca 颁发的证书,也可以使用自签名证书。

3.证书链

一般来说,我们将自己生成的 CSR 提交给签名商,他们用中级证书机构的私钥 Private Key 给我们的签名成证书,Root CA 通过它的私钥对中级机构提交的CSR进行签名。

证书颁发机构是一个树形结构的。比如在验证我们证书X的有效性的时候,会一层层的去寻找颁发者的证书,直到自签名的根证书,然后通过相应的公钥再反过来验证下一级的数字签名的正确性。直到找到X证书,这就是证书链(Certificate Chains)。

我们可以使用以下程序检查任何服务器的证书链: 

  1. func main() {  
  2. addr :flag.String("addr", "localhost:8360", "dial address")  
  3. flag.Parse()  
  4. cfg :tls.Config{}  
  5. conn, err :tls.Dial("tcp", *addr, &cfg)  
  6. if err != nil {  
  7. log.Fatal("TLS connection failed: " + err.Error())  
  8.  
  9. defer conn.Close()   
  10. certChain :conn.ConnectionState().PeerCertificates  
  11. for i, cert :range certChain { 
  12. fmt.Println(i)  
  13. fmt.Println("Issuer:", cert.Issuer)  
  14. fmt.Println("Subject:", cert.Subject)  
  15. fmt.Println("Version:", cert.Version)  
  16. fmt.Println("NotAfter:", cert.NotAfter)  
  17. fmt.Println("DNS names:", cert.DNSNames)  
  18. fmt.Println("")  
  19.  

给定IP地址后,启动程序后会与服务器建立一条 TLS 连接,并上报其使用的证书给服务端。如果我们使用未处理过的自签的证书,TLS 服务端验证是通不过的。所以我们需要权威ca 颁发的证书,或者使用 mkcert 为我们的服务器生成证书来使他生效。

打开终端,执行 mkcert 命令: 

  1. ➜  kangkai-iri ./mkcert localhost  
  2. ➜  kangkai-iri go run tls-socket-server.go -cert localhost.pem -key localhost-key.pem 

新打开一个终端,运行 tls-dial-port:

  1. ➜  kangkai-iri go run tls-dial-port.go -addr localhost:4040 

我们看到生成了证书 mkcert。由于 mkcert 将此证书添加到服务器的系统根存储中,直接使用 tls.Dial 将信任该证书。 

 

责任编辑:庞桂玉 来源: 马哥Linux运维
相关推荐

2020-08-04 10:10:12

DNS over TL系统运维

2011-03-08 14:14:31

Proftpd

2021-11-24 16:51:03

gRPCGoPython

2021-04-09 20:04:34

区块链Go加密

2015-05-13 09:45:13

2020-08-12 08:56:30

代码凯撒密码函数

2024-02-06 17:57:06

Go语言任务

2011-03-07 15:16:40

FileZilla SSSLTLS

2022-10-28 18:36:18

2024-02-23 07:18:40

JWTWeb应用程序

2023-10-31 22:54:17

GoEventBus驱动编程

2023-03-31 07:49:51

syscall库Echo Serve

2010-09-14 13:51:45

sql server恢

2023-04-18 08:27:16

日志级别日志包

2009-09-22 12:20:12

ibmdwLotus

2010-01-21 11:19:44

TCP Socketlinux

2009-06-08 09:22:07

数据访问优化SQL Server

2010-10-21 10:28:13

SQL Server查

2010-10-20 16:17:17

SQL Server角

2022-04-18 10:01:07

Go 语言汉诺塔游戏
点赞
收藏

51CTO技术栈公众号