https配置、雙向驗(yàn)證、go代碼實(shí)現(xiàn)

原理

參照這里: 雙向認(rèn)證SSL原理,已經(jīng)說的很詳細(xì)了

證書生成

根證書生成

openssl genrsa -out ca.key 2048
#這里可以使用 -subj 不用進(jìn)行交互 當(dāng)然還可以添加更多的信息
openssl req -x509 -new -nodes -key ca.key -subj "/CN=test" -days 5000 -out ca.crt

服務(wù)端證書生成

openssl genrsa -out server.key 2048
#這里的/cn可以是必須添加的 是服務(wù)端的域名 或者是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;
    # 開啟客戶端認(rèn)證
    ssl_verify_client on;
}

這里已經(jīng)可以進(jìn)行訪問,但是由于是自己簽發(fā)的證書,瀏覽器會提示不安全。需要在瀏覽器中添加例外(firefox),或者繼續(xù)訪問(chrome)

瀏覽器訪問后,出現(xiàn):no required SSL certificate was sent,說明瀏覽器已經(jīng)認(rèn)證了服務(wù)器,但是沒有找到證書發(fā)送給服務(wù)器,因此服務(wù)器對客戶端沒有認(rèn)證通過,就返回了400錯(cuò)誤。這個(gè)時(shí)候我們需要在瀏覽器中導(dǎo)入客戶端證書,讓雙向認(rèn)證完成。

把客戶端證書轉(zhuǎn)為client.p12格式,方便瀏覽器導(dǎo)入測試

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

瀏覽器導(dǎo)入 client.p12 后,已經(jīng)能正常訪問服務(wù)器了。

客戶端代碼測試

用客戶端代碼測試,能正常訪問,go實(shí)現(xiàn),其他的可能需要用到其他格式的證書,但只需要轉(zhuǎn)換一下格式即可:

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))
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容