SSL/TLS的工作过程为:
- 在浏览器中输入HTTPS协议的网址,比如 https://exmail.qq.com/
- 服务器向浏览器返回证书,浏览器检查该证书的合法性。
- 验证合法性
- 浏览器使用证书中的公钥加密一个随机对称密钥,并将加密后的密钥和使用密钥(对称密钥)加密后的请求URL一起发送到服务器。
- 服务器用私钥解密随机对称密钥,并用获取的密钥解密加密的请求URL。
- 服务器把用户请求的网页用密钥加密,并返回给用户。
- 用户浏览器用密钥解密服务器发来的网页数据,并将其显示出来。
下面是Golang socket编程中使用TLS示例代码。首先使用openssl生成私钥以及证书。
生成服务器端的私钥
openssl genrsa -out server.key 2048
生成服务器端证书
openssl req -new -x509 -key server.key -out server.pem -days 3650
服务端:
package main
import (
"bufio"
"crypto/tls"
"log"
"net"
)
func main() {
cert,err := tls.LoadX509KeyPair("server.pem","server.key")
if err != nil {
log.Println(err)
return
}
config := &tls.Config{Certificates: []tls.Certificate{cert}}
ln,err := tls.Listen("tcp","192.168.1.104:443",config)
if err != nil {
log.Println(err)
return
}
defer ln.Close()
for {
conn,err := ln.Accept()
if err != nil {
log.Println(err)
continue
}
go handleConn(conn)
}
}
func handleConn(conn net.Conn) {
defer conn.Close()
r := bufio.NewReader(conn)
for {
msg,err := r.ReadString('\n')
if err != nil {
log.Println(err)
return
}
println(msg)
n,err := conn.Write([]byte("world\n"))
if err != nil {
log.Println(n,err)
return
}
}
}
客户端
package main
import (
"crypto/tls"
"log"
)
func main() {
conf := &tls.Config{
InsecureSkipVerify: true,}
conn,err := tls.Dial("tcp","127.0.0.1:443",conf)
if err != nil {
log.Println(err)
return
}
defer conn.Close()
n,err := conn.Write([]byte("hello\n"))
if err != nil {
log.Println(n,err)
return
}
buf := make([]byte, 100)
n,err = conn.Read(buf)
if err != nil {
log.Println(n,err)
return
}
println(string(buf[:n]))
}
上面通信过程的抓包截图为,从抓包分析中可以看到数据是加密的:
参考:
《GO语音编程》
使用Go实现TLS 服务器和客户端
SSL/TLS 握手过程详解