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

1.TLS socket server

服务端示例
funcmain()
 {

  port := flag.String(
"port"
"8360"
"listening port"
)

  certFile := flag.String(
"cert"
"cert.pem"
"certificate PEM file"
)

  keyFile := flag.String(
"key"
"key.pem"
"key PEM file"
)

  flag.Parse()

  cert, err := tls.LoadX509KeyPair(*certFile, *keyFile)

if
 err != 
nil
 {

    log.Fatal(err)

  }

  config := &tls.Config{Certificates: []tls.Certificate{cert}}

  log.Printf(
"listening on port %s\n"
, *port)

  l, err := tls.Listen(
"tcp"
":"
+*port, config)

if
 err != 
nil
 {

    log.Fatal(err)

  }

defer
 l.Close()

for
 {

    conn, err := l.Accept()

if
 err != 
nil
 {

      log.Fatal(err)

    }

    log.Printf(
"accepted connection from %s\n"
, conn.RemoteAddr())

gofunc(c net.Conn)
 {

      io.Copy(c, c)

      c.Close()

      log.Printf(
"closing connection from %s\n"
, conn.RemoteAddr())

    }(conn)

  }

}

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

2.TLS socket client

客户端示例:
funcmain()
 {

  port := flag.String(
"port"
"8360"
"port to connect"
)

  certFile := flag.String(
"certfile"
"cert.pem"
"trusted CA certificate"
)

  flag.Parse()

  cert, err := os.ReadFile(*certFile)

if
 err != 
nil
 {

    log.Fatal(err)

  }

  certPool := x509.NewCertPool()

if
 ok := certPool.AppendCertsFromPEM(cert); !ok {

    log.Fatalf(
"unable to parse cert from %s"
, *certFile)

  }

  config := &tls.Config{RootCAs: certPool}

  conn, err := tls.Dial(
"tcp"
"localhost:"
+*port, config)

if
 err != 
nil
 {

    log.Fatal(err)

  }

  _, err = io.WriteString(conn, 
"Hello simple secure Server\n"
)

if
 err != 
nil
 {

    log.Fatal(
"client write error:"
, err)

  }

if
 err = conn.CloseWrite(); err != 
nil
 {

    log.Fatal(err)

  }

  buf := 
make
([]
byte
256
)

  n, err := conn.Read(buf)

if
 err != 
nil
 && err != io.EOF {

    log.Fatal(err)

  }

  fmt.Println(
"client read:"
string
(buf[:n]))

  conn.Close()

}

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

3.证书链

一般来说,我们将自己生成的 CSR 提交给签名商,他们用中级证书机构的私钥 Private Key 给我们的签名成证书,Root CA 通过它的私钥对中级机构提交的CSR进行签名。
证书颁发机构是一个树形结构的。比如在验证我们证书X的有效性的时候,会一层层的去寻找颁发者的证书,直到自签名的根证书,然后通过相应的公钥再反过来验证下一级的数字签名的正确性。直到找到X证书,这就是证书链(Certificate Chains)。
我们可以使用以下程序检查任何服务器的证书链:
funcmain()
 {

addr := flag.String(
"addr"
"localhost:8360"
"dial address"
)

flag.Parse()


cfg := tls.Config{}

conn, err := tls.Dial(
"tcp"
, *addr, &cfg)

if
 err != 
nil
 {

log.Fatal(
"TLS connection failed: "
 + err.Error())

}

defer
 conn.Close()


certChain := conn.ConnectionState().PeerCertificates

for
 i, cert := 
range
 certChain {

fmt.Println(i)

fmt.Println(
"Issuer:"
, cert.Issuer)

fmt.Println(
"Subject:"
, cert.Subject)

fmt.Println(
"Version:"
, cert.Version)

fmt.Println(
"NotAfter:"
, cert.NotAfter)

fmt.Println(
"DNS names:"
, cert.DNSNames)

fmt.Println(
""
)

}

}

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


➜  kangkai-iri go run tls-socket-server.go -cert localhost.pem -key localhost-key.pem

新打开一个终端,运行 tls-dial-port:
➜  kangkai-iri go run tls-dial-port.go -addr localhost:4040

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

(版权归原作者所有,侵删)

点击下方“阅读原文”查看更多
继续阅读
阅读原文