需要安装好 go 1.15 以下的版本

HTTP

直接监听在 8080 端口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main

import (
"fmt"
"net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hi, This is an example of http service in golang!")
}

func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
image.png
image.png

HTTPS 忽略服务端证书校验

用 ListenAndServeTLS 来替换掉 ListenAndServe,需要指定服务端的证书和私钥

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main

import (
"fmt"
"net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hi, This is an example of https service in golang!")
}

func main() {
http.HandleFunc("/", handler)
http.ListenAndServeTLS(":8081", "server.crt", "server.key", nil)
}

这时候会提示风险,接受风险后正常访问

image.png
image.png
image.png
image.png

接下来使用 go 写一个客户端来进行连接
(github 上面下载的证书过期了,重新生成一下
openssl genrsa -out server.key 2048 #生成私钥
openssl req -new -x509 -key server.key -out server.crt -days 365 #生成证书

image.png
image.png

)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package main

import (
"fmt"
"io/ioutil"
"net/http"
)

func main() {
resp, err := http.Get("https://localhost:8081")
if err != nil {
fmt.Println("error:", err)
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
fmt.Println(string(body))
}

请求的时候报了一个错误,意思是客户端认为证书不是由知名的 CA 签发的

image.png
image.png

修改客户端的代码,略过对证书的校验

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main

import (
"crypto/tls"
"fmt"
"io/ioutil"
"net/http"
)

func main() {
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
client := &http.Client{Transport: tr}
resp, err := client.Get("https://localhost:8081")

if err != nil {
fmt.Println("error:", err)
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
fmt.Println(string(body))
}

HTTPS 对服务端证书进行校验

多数时候需要对服务端证书进行校验,而不是像上面那样忽略这个校验,通过校验我们可以确认:1、服务端传来的证书是由某个特定 CA 签发的(如果是 self-signed,也无妨)2、服务端传来的数字证书没有被中途篡改过
接下来建立一个属于自己的 CA

1
2
3
4
5
6
7
8
9
10
#生成一个ca私钥
openssl genrsa -out ca.key 2048
#生成一个ca证书
openssl req -x509 -new -nodes -key ca.key -subj "/CN=localhost" -days 5000 -out ca.crt
#生成服务端私钥
openssl genrsa -out server.key 2048
#生成服务端证书请求
openssl req -new -key server.key -subj "/CN=localhost" -out server.csr
#用我们的ca私钥签发server的数字证书
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 5000

此时先用客户端加载 ca 证书

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
package main

import (
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"net/http"
)

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)

tr := &http.Transport{
TLSClientConfig: &tls.Config{RootCAs: pool},
}
client := &http.Client{Transport: tr}
resp, err := client.Get("https://localhost:8081")
if err != nil {
fmt.Println("Get error:", err)
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
fmt.Println(string(body))
}

HTTPS 双向校验

服务端对客户端的证书进行校验

1
2
3
4
5
6
#生成客户端私钥
openssl genrsa -out client.key 2048
#生成客户端证书请求
openssl req -new -key client.key -subj "/CN=localhost_cn" -out client.csr
#使用ca生成对客户端证书
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 5000
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

package main

import (
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"net/http"
)

type myhandler struct {
}

func (h *myhandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hi, This is an example of http service in golang!\n")
}

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)

s := &http.Server{
Addr: ":8081",
Handler: &myhandler{},
TLSConfig: &tls.Config{
ClientCAs: pool,
ClientAuth: tls.RequireAndVerifyClientCert,
},
}

err = s.ListenAndServeTLS("server.crt", "server.key")
if err != nil {
fmt.Println("ListenAndServeTLS err:", err)
}
}
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
package main

import (

"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"net/http"
)

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},
},
}
client := &http.Client{Transport: tr}
resp, err := client.Get("https://localhost:8081")
if err != nil {
fmt.Println("Get error:", err)
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
fmt.Println(string(body))
}

通是通了,但是抓包看不到区别

参考: