1.单向认证

单向认证SSL协议不需要客户拥有CA证书。站点部署了ssl证书就行,任何用户都可以去访问(IP被限制除外等),仅服务端提供身份认证。client需要一个ca.crt,服务器需要server.crt、server.key。

2.最简单的https server

2.1制作证书

openssl genrsa -out server.key 2048
openssl req -new -x509 -key server.key -out server.crt -days 365

2.2编写程序https.go

package main
import(
    "fmt"
    "net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w,
        "Hi, This is a https service")
}

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

2.3启动服务

go run https.go 

2.4运行结果

curl -k https://127.0.0.1:9090

Hi, This is a https service

-k表示忽略验证证书,不验证服务端。

2.5调用代码

package main
import(
    "fmt"
    "io/ioutil"
    "net/http"
)
func main() {
    resp, err := http.Get("https://tim:9090")
    if err != nil {
        fmt.Println("error:", err)
        return
    }
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    fmt.Println(string(body))
}

2.6运行结果

error: Get https://tim:9090: x509: certificate signed by unknown authority因为自己的证书未认证。

3.跳过证书验证

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://tim:9090")

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

上面的tim需要注意,如果设置验证证书的话(TLSClientConfig: &tls.Config{InsecureSkipVerify: false}),那么需要验证两个东西,一个是上证书用的CN的名称一致。

x509: cannot validate certificate for 127.0.0.1 because it doesn't contain any IP SANs

另一个是证书是否权威签发,否则就是上面的unknown authority了如果设置成true,则无所谓了,不校验证书,当然不一致也无所谓了。

4.校验服务端

4.1安全建立连接

openssl genrsa -out ca.key 2048
openssl req -x509 -new -nodes -key ca.key -subj "/CN=tim" -days 5000 -out ca.crt

openssl genrsa -out server.key 2048
openssl req -new -key server.key -subj "/CN=tim" -out server.csr
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 := "/mnt/go/src/test/clinet/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://tim:9090")
    if err != nil {
        fmt.Println("Get error:", err)
        return
    }
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    fmt.Println(string(body))
}

4.2运行结果

Hi, This is a https service