概述
IEFT 在 SSL v3.0 的基础上制定了 SSL 的互联网标准版本,称为传输层安全(Transport Layer Security, TLS)协议。其目标是使 SSL 更安全,并使协议的规范更精确和完善。IEFT 在后续发布的 RFC 中建议禁用 SSL。
TLS 主要经历了 4 个版本:TLS 1.0 (RFC2246, 1999年),TLS 1.1(RFC4346, 2006年),TLS 1.2 (RFC5246, 2008年),TLS 1.3(RFC8446, 2018年)。
TLS 协议
协议栈体系结构

TLS 握手
TLS v1.2 的握手流程如下图所示,假设使用基于 RSA 的密钥交换算法:

在 ClientHello 消息中的密码套件(cipher suite) 参数格式如下(TLS v1.2):

参考 Analyze TLS and mTLS Authentication with Wireshark。
Demo 测试
本节使用 Go 建立基于 TLS 的 C/S 通信,并使用 wireshark 解析通信协议报文。
生成证书
为了使用 TLS,我们首先需要生成一系列 TLS 证书。由于我们不是部署到生产环境,我们可以使用自签名证书;反之,我们需要从一个可信的 CA 获取证书。
a. 生成私钥
1
| $ openssl genrsa -out server.key 2048
|
b. 生成自签名证书
1
| $ openssl req -new -x509 -key server.key -out server.crt -days 365 -addext "subjectAltName = DNS:localhost"
|
编写 server 端代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| package main
import ( "bufio" "crypto/tls" "fmt" "log" "net" )
func main() { cert, err := tls.LoadX509KeyPair("certificates/server.crt", "certificates/server.key") if err != nil { log.Fatal(err) } fmt.Println("Server start listening on port 443") ln, err := tls.Listen("tcp", ":443", &tls.Config{Certificates: []tls.Certificate{cert}}) if err != nil { log.Fatal(err) return } defer ln.Close() for { conn, err := ln.Accept() if err != nil { log.Fatal(err) continue } go handler(conn) } }
func handler(conn net.Conn) { defer conn.Close() r := bufio.NewReader(conn) for { msg, err := r.ReadString('\n') if err != nil { log.Println(err) return } fmt.Println(msg) _, err = conn.Write([]byte("world\n")) if err != nil { log.Println(err) return } } }
|
编写 client 端代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| package main
import ( "crypto/tls" "fmt" "log" )
func main() { conn, err := tls.Dial("tcp", "localhost:443", &tls.Config{InsecureSkipVerify: true}) if err != nil { log.Fatal(err) } defer conn.Close() _, err = conn.Write([]byte("Hello\n")) if err != nil { log.Fatal(err) } buf := make([]byte, 1024) n, err := conn.Read(buf) if err != nil { log.Fatal(err) } fmt.Println(string(buf[:n])) }
|
TLS扩展和高级特性
TLS 协议不仅提供基本的加密和身份认证功能,还包括多种扩展和高级特性,这些特性可以优化性能、增强安全性,或支持特定的安全场景。
SNI
SNI(Server Name Indication) 扩展允许多个域名共享同一个 IP 地址和端口,但同时使用不同的证书。在 Go 中,可以通过 tls.config 的 NameToCertificate 字段来实现 SNI。
1 2 3 4 5 6
| config := &tls.Config { NameToCertificate: map[string]*tls.Certificate { "example.com" : cert1, "example.org" : cert2 } }
|
ALPN
ALPN(Application-Layer Protocol Negotiation) 扩展允许客户端和服务器在 TLS 握手过程中协商应用层协议(如 HTTP)。在 Go 的 tls.config 中,可以设置 NextProtos 来实现 ALPN。
1 2 3
| config := &tls.Config { NextProtos: []string{"h2", "http/1.1"} }
|