Go代码打通HTTPs
TL;DR 手工创建CA证书链,手写代码打通HTTPs的两端 HTTPs最近是一个重要的话题,同时也是一个有点难懂的话题。所以网上有大量的HTTPs/TLS/SSL的教程。关于这些的原理,这里不做讲解,有兴趣的可以自行搜索。 本文介绍一个自己创建证书,并编写 Go 代码实现 client/server 两端的过程。从实践的角度帮助理解。 构建 CA 证书链我们首先要创建 client/server 使用的证书。创建证书的方法有很多种:有不怕麻烦,直接通过 openssl
在 shell 里面执行一下的命令:
就这样,我们就为域名 testca/ cacert.pem server/ cert.pem key.pem 编写服务接下来开始写代码。Go 对 TLS 的支持还是比较完备的,也比较简单。以下是服务器端的代码 func HelloServer(w http.ResponseWriter,req *http.Request) { w.Header().Set("Content-Type","text/plain") w.Write([]byte("This is an example server.n")) } func main() { http.HandleFunc("/hello",HelloServer) err := http.ListenAndServeTLS(":1443","server/cert.pem","server/key.pem",nil) if err != nil { log.Fatal("ListenAndServe: ",err) } } 可以看到我们创建了一个 HTTP 服务,这个服务监听 1443 端口并且只处理一个路径 ListenAndServeTLS(addr,certFile,keyFile string,handler Handler) 运行服务程序: go run server.go 访问HTTPs服务假定我们的服务程序是运行在本地的。我们先改一下 # echo 127.0.0.1 www.mytestdomain.io >> /etc/hosts 我们用以下的代码 func main() { client := &http.Client{} resp,err := client.Get("https://www.mytestdomain.io:1443/hello") if err != nil { panic("failed to connect: " + err.Error()) } content,_ := ioutil.ReadAll(resp.Body) s := strings.TrimSpace(string(content)) fmt.Println(s) } 运行 panic: failed to connect: Get https://www.mytestdomain.io:1443/hello: x509: certificate signed by unknown authorit 这是因为系统不知道如何来处理这个 self signed 证书。 各个 OS 添加根证书的方法是不同的。对于 Linux 系统 (以 Ubuntu 为例) 来说,把证书文件放到相应的目录即可: # sudo cp testca/cacert.pem /etc/ssl/certs 如果是 macOS,可以用一下的命令: # sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain testca/cacert.pem 上面的方法会把我们手工创建的 root CA 现在我们再次运行刚才那个程就会成功的获得服务端的响应了: This is an example server. 另一种访问方法假如只是一个普通的用户,没有 root/sudo 权限,不就无法做上面的操作了吗?这种情况下还有另外一种做法: 把 root CA 放置在代码里面。 在上面的 func main() { roots := x509.NewCertPool() ok := roots.AppendCertsFromPEM([]byte(rootPEM)) if !ok { panic("failed to parse root certificate") } tr := &http.Transport{ TLSClientConfig: &tls.Config{RootCAs: roots},} client := &http.Client{Transport: tr} // ... 其中的 var rootPEM = ` -----BEGIN CERTIFICATE----- MIIDAjCCAeqgAwIBAgIJAL2faqa73yLvMA0GCSqGSIb3DQEBCwUAMDExIDAeBgNV BAMMF1RMU0dlblNlbGZTaWduZWR0Um9vdENBMQ0wCwYDVQQHDAQkJCQkMB4XDTE4 MDIwNTA5Mzc0NVoXDTI4MDIwMzA5Mzc0NVowMTEgMB4GA1UEAwwXVExTR2VuU2Vs ZlNpZ25lZHRSb290Q0ExDTALBgNVBAcMBCQkJCQwggEiMA0GCSqGSIb3DQEBAQUA A4IBDwAwggEKAoIBAQC9eO6Tam4XFDUbK9FAStAg29teYeKtt8WEJvKGB50xMfXO 2pD0StsXhKrspXBYck0FwKIBsTLr97w7dSqa64z3U2V2BorogFzoEE4JH2sydYGA QqNAqezGx8VZnQVRyZEBifRPebR4WVD5GtXYe+MnSkHPIgsG0QG0SaiSfMl05dSJ HoE9T9Kly9fH6yED88++OYjZZRGKOf2THpQlXJjF3iwCDLkwz9Z/kjmpK/rR0SEh tanf7bOgGs3OoFmX4DvmFJXoriVUC9jcj0Z4oX3Ld81XXyd4FJkpKvdKDhYkqcug FgERqdBeRDM+MA38YooKHZh0klL2EThNXJxM0r1vAgMBAAGjHTAbMAwGA1UdEwQF MAMBAf8wCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBCwUAA4IBAQBEqp0ON1A/pCKF ztfKuzdW+9pauE8dl6Ij3++dt6AqW5QYFLOEFQwoMBOkGChGQDxHkakyaA0DfGe5 JntMH0yYyZnr4kfs+AcY6P+2PfgrgVBqadhR6uAGOBaXDW7dlllqIJJ8NRInA/fT DYXMxBJbFrcj2cGIYVPvAbrosZ5L/YdAdVM76V8uuk8Hmmy5zRQj+gWt/jDkYWFr p0b6k3FBXvM7+nhqAIdyMjLioAdYwFpPglGj3xHXS5neWjyUDlAYISNe+PKMERSe DrptyDE+ljzl77hvvfZD9OPhXbDkAeVU/NaDwHG/G5HDVdNbg/FZ6ueevF34Xuze jm3lrdJm -----END CERTIFICATE-----` 也就是说,我们用准备好的 root CA 的内容产生了一个新的 http transport。 运行一下 This is an example server. 总结一对 HTTPs client/server 程序中需要一个共同的 root CA。服务器端需要该 root CA 创建的 CA/私钥对。 这里用的是 Go 语言来实现,其它的语言过程也类似。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |