本篇文章是基于实操,如何在本地环境用GO实现HTTPS链接。原理部分请参考文章《【深度知识】HTTPS协议原理和流程分析》。
按照《TLS完全指南(二):OpenSSL操作指南》文档操作,最终失败。
在浏览器输入"https://localhost/",发现提示为"访问 localhost 的请求遭到拒绝 您未获授权,无法查看此网页。HTTP ERROR 403"。
在linux下使用,提示原因如下。辉哥认为自认证产生的证书不可使用。
[root@iZ23prr3ucfZ server]# curl --cacert cert.pem https://localhost
curl: (60) Peer certificate cannot be authenticated with known CA certificates
More details here: http://curl.haxx.se/docs/sslcerts.html
curl performs SSL certificate verification by default, using a "bundle"
of Certificate Authority (CA) public keys (CA certs). If the default
bundle file isn't adequate, you can specify an alternate file
using the --cacert option.
If this HTTPS server uses a certificate signed by a CA represented in
the bundle, the certificate verification probably failed due to a
problem with the certificate (it might be expired, or the name might
not match the domain name in the URL).
If you'd like to turn off curl's verification of the certificate, use
the -k (or --insecure) option.
放弃该篇文章方法尝试。
tls-gen是一个用 Python 编写的、非常易用的工具。它定义了三种 profile。这里我们选择最简单的一种:一个根证书和一组证书、私钥对。
在linux系统 shell 里面执行一下的命令:
git clone https://github.com/michaelklishin/tls-gen cd tls-gen/basic make CN=localhost
就这样,我们就为域名 localhost创建了一套证书。观察一下当前路径的内容,我们会发现两个新的目录:testca 和 server。前者里面存放了刚刚创建的根证书 (root CA),后者里面存放了我们之后的服务程序要用的的证书和私钥。
testca/ cacert.pem server/ cert.pem key.pem
这是成功的命令输出结果:
[root@iZ23prr3ucfZ tmp]# git clone https://github.com/michaelklishin/tls-gen
Initialized empty Git repository in /root/tmp/tls-gen/.git/
remote: Enumerating objects: 369, done.
remote: Total 369 (delta 0), reused 0 (delta 0), pack-reused 369
Receiving objects: 100% (369/369), 90.46 KiB | 117 KiB/s, done.
Resolving deltas: 100% (215/215), done.
[root@iZ23prr3ucfZ tmp]# ls
server.crt server.csr server.go server.key tls-gen
[root@iZ23prr3ucfZ tmp]# cd tls-gen/basic
[root@iZ23prr3ucfZ basic]# make CN=localhost
python3 profile.py regenerate --password "" \
--common-name localhost \
--client-alt-name iZ23prr3ucfZ \
--server-alt-name iZ23prr3ucfZ \
--days-of-validity 3650 \
--key-bits 2048
Removing /root/tmp/tls-gen/basic/testca
Removing /root/tmp/tls-gen/basic/result
Removing /root/tmp/tls-gen/basic/server
Removing /root/tmp/tls-gen/basic/client
Will generate a root CA and two certificate/key pairs (server and client)
=> [openssl_req]
Generating a 2048 bit RSA private key
..................................+++
.............................................................+++
writing new private key to '/root/tmp/tls-gen/basic/testca/private/cakey.pem'
-----
=> [openssl_x509]
Will generate leaf certificate and key pair for server
Using localhost for Common Name (CN)
Using parent certificate path at /root/tmp/tls-gen/basic/testca/cacert.pem
Using parent key path at /root/tmp/tls-gen/basic/testca/private/cakey.pem
Will use RSA...
=> [openssl_genrsa]
Generating RSA private key, 2048 bit long modulus
............................................+++
...............................................................................................+++
e is 65537 (0x10001)
=> [openssl_req]
=> [openssl_ca]
Using configuration from /tmp/tmpdaabupsr
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
commonName :PRINTABLE:'localhost'
organizationName :PRINTABLE:'server'
localityName :T61STRING:'$$$$'
Certificate is to be certified until May 6 06:24:49 2029 GMT (3650 days)
Write out database with 1 new entries
Data Base Updated
Will generate leaf certificate and key pair for client
Using localhost for Common Name (CN)
Using parent certificate path at /root/tmp/tls-gen/basic/testca/cacert.pem
Using parent key path at /root/tmp/tls-gen/basic/testca/private/cakey.pem
Will use RSA...
=> [openssl_genrsa]
Generating RSA private key, 2048 bit long modulus
..............+++
............+++
e is 65537 (0x10001)
=> [openssl_req]
=> [openssl_ca]
Using configuration from /tmp/tmpdaabupsr
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
commonName :PRINTABLE:'localhost'
organizationName :PRINTABLE:'client'
localityName :T61STRING:'$$$$'
Certificate is to be certified until May 6 06:24:49 2029 GMT (3650 days)
Write out database with 1 new entries
Data Base Updated
Done! Find generated certificates and private keys under ./result!
python3 profile.py verify
Will verify generated certificates against the CA...
Will verify client certificate against root CA
/root/tmp/tls-gen/basic/result/client_certificate.pem: OK
Will verify server certificate against root CA
/root/tmp/tls-gen/basic/result/server_certificate.pem: OK
Go 对 TLS 的支持还是比较完备。以下是服务器端的代码(server.go):
package main
import (
"log"
"net/http"
)
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 端口并且只处理一个路径 /hello。然后调用了下面这个函数来监听 1443 端口。注意我们给出了之前创建的服务的证书和私钥 - 这样就保证了HTTP会用加密的方式来传输。
运行服务程序:
go run server.go
编写客户端程序(client.go):
package main
import (
"net/http"
"fmt"
"io/ioutil"
"strings"
)
func main() {
client := &http.Client{}
resp, err := client.Get("https://localhost:1443/hello")
if err != nil {
panic("failed to connect: " + err.Error())
}
content, _ := ioutil.ReadAll(resp.Body)
s := strings.TrimSpace(string(content))
fmt.Println(s)
}
运行 go run client.go,有这样的错误:
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
如果是WINDOWS,则在浏览器上把"testca/cacert.pem"导入到“受信任的根证书颁发机构”。
现在我们再次运行刚才那个程就会成功的获得服务端的响应了:
This is an example server.
在浏览器上输入https://localhost:1443/hello可以有正常输出:
修改client.go文件为直接读取PEM文件的方式。
package main
import (
"net/http"
"fmt"
"io/ioutil"
"strings"
"crypto/x509"
"crypto/tls"
)
func main() {
rootPEM, err := ioutil.ReadFile("testca/cacert.pem")
if err != nil {
fmt.Print(err)
}
roots := x509.NewCertPool()
ok := roots.AppendCertsFromPEM(rootPEM)
if !ok {
panic("failed to parse root certificate")
}
tr := &http.Transport{
TLSClientConfig: &tls.Config{RootCAs: roots},
}
client := &http.Client{Transport: tr}
resp, err := client.Get("https://localhost:1443/hello")
if err != nil {
panic("failed to connect: " + err.Error())
}
content, _ := ioutil.ReadAll(resp.Body)
s := strings.TrimSpace(string(content))
fmt.Println(s)
}
也就是说,我们用准备好的 root CA 的内容产生了一个新的 http transport。
运行一下 go run client.go。成功!
This is an example server.
(1)Go代码打通HTTPs
https://studygolang.com/articles/12401
(2)TLS完全指南(一):TLS和安全通信
https://zhuanlan.zhihu.com/p/26684050
TLS完全指南(二):OpenSSL操作指南实际操作失败
https://zhuanlan.zhihu.com/p/26684071
TLS完全指南(三):用Go语言写HTTPS程序
https://zhuanlan.zhihu.com/p/26684081
(3)Go实战--golang中使用HTTPS以及TSL(.crt、.key、.pem区别以及crypto/tls包介绍)GITHUB
https://blog.csdn.net/wangshubo1989/article/details/77508738
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有