HTTPS单向认证和双向认证
HTTPS单向认证和双向认证
需要安装好 go 1.15 以下的版本
HTTP
直接监听在 8080 端口
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)
}
HTTPS忽略服务端证书校验
用 ListenAndServeTLS 来替换掉 ListenAndServe,需要指定服务端的证书和私钥
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)
}
这时候会提示风险,接受风险后正常访问
接下来使用 go 写一个客户端来进行连接
(github上面下载的证书过期了,重新生成一下
openssl genrsa -out server.key 2048 #生成私钥
openssl req -new -x509 -key server.key -out server.crt -days 365 #生成证书
)
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签发的
修改客户端的代码,略过对证书的校验
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
#生成一个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证书
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双向校验
服务端对客户端的证书进行校验
#生成客户端私钥
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
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)
}
}
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))
}
通是通了,但是抓包看不到区别
参考:
experiments/gohttps at master · bigwhite/experiments