https配置、双向验证、go代码实现

2019-11-14  本文已影响0人  被误认为吃货的程序猿

原理

参照这里: 双向认证SSL原理,已经说的很详细了

证书生成

根证书生成

openssl genrsa -out ca.key 2048
#这里可以使用 -subj 不用进行交互 当然还可以添加更多的信息
openssl req -x509 -new -nodes -key ca.key -subj "/CN=test" -days 5000 -out ca.crt

服务端证书生成

openssl genrsa -out server.key 2048
#这里的/cn可以是必须添加的 是服务端的域名 或者是etc/hosts中的ip别名
openssl req -new -key server.key -subj "/CN=server" -out server.csr
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 5000

客户端证书生成

openssl genrsa -out client.key 2048
openssl req -new -key client.key -subj "/CN=client" -out client.csr
echo extendedKeyUsage=clientAuth > extfile.cnf
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -extfile extfile.cnf -out client.crt -days 5000 

nginx 配置

server {
    listen 443 ssl;
    ssl_certificate server.crt;
    ssl_certificate server.key;
    ssl_client_certificate ca.crt;
    # 开启客户端认证
    ssl_verify_client on;
}

这里已经可以进行访问,但是由于是自己签发的证书,浏览器会提示不安全。需要在浏览器中添加例外(firefox),或者继续访问(chrome)

浏览器访问后,出现:no required SSL certificate was sent,说明浏览器已经认证了服务器,但是没有找到证书发送给服务器,因此服务器对客户端没有认证通过,就返回了400错误。这个时候我们需要在浏览器中导入客户端证书,让双向认证完成。

把客户端证书转为client.p12格式,方便浏览器导入测试

openssl pkcs12 -export -clcerts -in client.crt -inkey client.key -out client.p12

浏览器导入 client.p12 后,已经能正常访问服务器了。

客户端代码测试

用客户端代码测试,能正常访问,go实现,其他的可能需要用到其他格式的证书,但只需要转换一下格式即可:

package main

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

func main() {
    pool := x509.NewCertPool()
    caCertPath := "certs/cert_server/ca.crt"

    caCrt, err := ioutil.ReadFile(caCertPath)
    if err != nil {
        fmt.Println("ReadFile err:", err)
        return
    }
    pool.AppendCertsFromPEM(caCrt)

    cliCrt, err := tls.LoadX509KeyPair("certs/cert_server/client.crt", "certs/cert_server/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}
    resp, err := client.Get("https://server:8081")
    if err != nil {
        fmt.Println("Get error:", err)
        return
    }
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    fmt.Println(string(body))
}
上一篇下一篇

猜你喜欢

热点阅读