HTTPS的一种简单实现
生成密钥、证书
第一步,为服务器端和客户端准备公钥、私钥
生成服务器端私钥
代码语言:txt复制openssl genrsa -out server.key 1024
生成服务器端公钥
代码语言:txt复制openssl rsa -in server.key -pubout -out server.pem
生成客户端私钥
代码语言:txt复制openssl genrsa -out client.key 1024
生成客户端公钥
代码语言:txt复制openssl rsa -in client.key -pubout -out client.pem
第二步,生成 CA 证书
生成 CA 私钥
代码语言:txt复制openssl genrsa -out ca.key 1024
X.509 Certificate Signing Request (CSR) Management.
代码语言:txt复制openssl req -new -key ca.key -out ca.csr
X.509 Certificate Data Management.
代码语言:txt复制openssl x509 -req -in ca.csr -signkey ca.key -out ca.crt
在执行第二步时
Common Name (e.g. server FQDN or YOUR name) []: 这一项,是最后可以访问的域名,为了方便测试,写成 test.com
如果想通过IP直接访问而不想通过域名,在创建服务端证书时:用如下语句:
代码语言:txt复制openssl genrsa -out server.key 2048
openssl req -new -key server.key -subj "/CN=192.168.1.10" -out server.csr
echo subjectAltName = IP:192.168.1.10 > extfile.cnf
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -extfile extfile.cnf -out server.crt -days 5000
第三步,生成服务器端证书和客户端证书
服务器端需要向 CA 机构申请签名证书,在申请签名证书之前依然是创建自己的 CSR 文件
代码语言:txt复制openssl req -new -key server.key -out server.csr
向自己的 CA 机构申请证书,签名过程需要 CA 的证书和私钥参与,最终颁发一个带有 CA 签名的证书
代码语言:txt复制openssl x509 -req -CA ca.crt -CAkey ca.key -CAcreateserial -in server.csr -out server.crt
client 端
代码语言:txt复制openssl req -new -key client.key -out client.csr
client 端到 CA 签名
代码语言:txt复制openssl x509 -req -CA ca.crt -CAkey ca.key -CAcreateserial -in client.csr -out client.crt
第四步,客户端机器添加test.com域名
代码语言:txt复制sudo vim /etc/hosts
添加服务端的ip信息对应的域名:192.168.1.100 test.com
源码实现
服务端代码
代码语言:javascript复制package main
import (
"net/http"
"log"
"crypto/x509"
"io/ioutil"
"fmt"
"crypto/tls"
)
type myhandler struct {
}
func (h *myhandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Content-Type", "text/plain")
w.Write([]byte("This is an example servern"))
}
func getHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "hello, this is https get ")
}
func postHandler(w http.ResponseWriter, r *http.Request) {
body, _ := ioutil.ReadAll(r.Body)
r.Body.Close()
body_str := string(body)
fmt.Println(body_str)
//ret, _ := json.Marshal(user)
ret := "{"code":200}"
fmt.Fprint(w, string(ret))
}
func main() {
pool := x509.NewCertPool()
caCertPath := "ca.crt"
caCrt, err := ioutil.ReadFile(caCertPath)
if err != nil {
fmt.Println("ReadFile err", err)
return
}
pool.AppendCertsFromPEM(caCrt)
server := http.NewServeMux()
server.HandleFunc("/get",getHandler)
server.HandleFunc("/post",postHandler)
s := &http.Server{
Addr: ":8088",
//Handler: &myhandler{},
Handler: server,
TLSConfig: &tls.Config{
ClientCAs: pool,
ClientAuth: tls.RequireAndVerifyClientCert,
},
}
log.Printf("About to listen on 10443.Go to https://127.0.0.1:8088")
err = s.ListenAndServeTLS("server.crt", "server.key")
if err != nil {
log.Fatal(err)
}
}
客户端代码
代码语言:javascript复制package main
import (
"net/http"
"fmt"
"io/ioutil"
"crypto/tls"
"crypto/x509"
"bytes"
)
func main() {
pool := x509.NewCertPool()
caCertPath := "ca.crt"
caCrt, err := ioutil.ReadFile(caCertPath)
if err != nil {
fmt.Println("ReadFile err", err)
return
}
pool.AppendCertsFromPEM(caCrt)
cliCrt, err := tls.LoadX509KeyPair("client.crt", "client.key")
if err != nil {
fmt.Println("LoadX509KeyPair err:", err)
return
}
tr := &http.Transport{
TLSClientConfig: &tls.Config{
RootCAs: pool,
Certificates: []tls.Certificate{cliCrt},
InsecureSkipVerify: true,//客户端关闭对服务端的验证
},
}
client := &http.Client{Transport: tr}
jsonStr := "{"name":"wang","age":29}"
req := bytes.NewBuffer([]byte(jsonStr))
body_type := "application/json;charset=utf-8"
resp, err := client.Post("https://test.com:8088/post",body_type,req)
if err != nil {
fmt.Println("Get error:", err)
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
fmt.Println(string(body))
}