Go代碼打通HTTPs

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

TL;DR 手工建立CA憑證鏈結,手寫代碼打通HTTPs的兩端

HTTPs最近是一個重要的話題,同時也是一個有點難懂的話題。所以網上有大量的HTTPs/TLS/SSL的教程。關於這些的原理,這裡不做講解,有興趣的可以自行搜尋。

本文介紹一個自己建立認證,並編寫 Go 代碼實現 client/server 兩端的過程。從實踐的角度協助理解。

構建 CA 憑證鏈

我們首先要建立 client/server 使用的認證。建立認證的方法有很多種:有不怕麻煩,直接通過 openssl
建立的,有通過 cfssl 建立的。這裡要介紹的是我認為最簡單的一種:tls-gen

tls-gen是一個用 Python 編寫的、非常易用的工具。它定義了三種 profile。這裡我們選擇最簡單的一種:一個根憑證和一組認證、私密金鑰對。

在 shell 裡面執行一下的命令:

  1. git clone https://github.com/michaelklishin/tls-gen
  2. cd tls-gen/basic
  3. make CN=www.mytestdomain.io

就這樣,我們就為網域名稱 www.mytestdomain.io 建立了一套認證。觀察一下當前路徑的內容,我們會發現兩個新的目錄:testcaserver。前者裡面存放了剛剛建立的根憑證 (root CA),後者裡面存放了我們之後的服務程式要用的的認證和私密金鑰。

testca/  cacert.pemserver/  cert.pem  key.pem

編寫服務

接下來開始寫代碼。Go 對 TLS 的支援還是比較完備的,也比較簡單。以下是伺服器端的代碼 (server.go):

func HelloServer(w http.ResponseWriter, req *http.Request) {    w.Header().Set("Content-Type", "text/plain")    w.Write([]byte("This is an example server.\n"))}func main() {    http.HandleFunc("/hello", HelloServer)    err := http.ListenAndServeTLS(":1443", "server/cert.pem", "server/key.pem", nil)    if err != nil {        log.Fatal("ListenAndServe: ", err)    }}

可以看到我們建立了一個 HTTP 服務,這個服務監聽 1443 連接埠並且只處理一個路徑 /hello。然後調用了下面這個函數來監聽 1443 連接埠。注意我們給出了之前建立的服務的認證和私密金鑰 - 這樣就保證了HTTP會用加密的方式來傳輸。

ListenAndServeTLS(addr, certFile, keyFile string, handler Handler)

運行服務程式:

go run server.go

訪問HTTPs服務

假定我們的服務程式是運行在本地的。我們先改一下 /etc/hosts 來佈建網域名解析:

# echo 127.0.0.1 www.mytestdomain.io >> /etc/hosts

我們用以下的代碼 (client.go) 來訪問服務:

func main() {    client := &http.Client{}    resp, err := client.Get("https://www.mytestdomain.io:1443/hello")    if err != nil {        panic("failed to connect: " + err.Error())    }    content, _ := ioutil.ReadAll(resp.Body)    s := strings.TrimSpace(string(content))    fmt.Println(s)}

運行 go run client.go,只能得到這樣的錯誤:

panic: failed to connect: Get https://www.mytestdomain.io:1443/hello: x509: certificate signed by unknown authorit

這是因為系統不知道如何來處理這個 self signed 認證。

各個 OS 添加根憑證的方法是不同的。對於 Linux 系統 (以 Ubuntu 為例) 來說,把認證檔案放到相應的目錄即可:

# sudo cp testca/cacert.pem /etc/ssl/certs

如果是 macOS,可以用一下的命令:

# sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain  testca/cacert.pem

上面的方法會把我們手工建立的 root CA
添加到系統所已知的列表裡面。這樣一來,所有用該 root CA
建立的認證都可以被認證了。

現在我們再次運行剛才那個程就會成功的獲得服務端的響應了:

This is an example server.

另一種存取方法

假如只是一個普通的使用者,沒有 root/sudo 許可權,不就無法做上面的操作了嗎?這種情況下還有另外一種做法: 把 root CA 放置在代碼裡面。

在上面的 client.go 裡面添加這麼幾行代碼:

func main() {    roots := x509.NewCertPool()    ok := roots.AppendCertsFromPEM([]byte(rootPEM))    if !ok {        panic("failed to parse root certificate")    }    tr := &http.Transport{        TLSClientConfig: &tls.Config{RootCAs: roots},    }    client := &http.Client{Transport: tr}    // ...

其中的 rootPEM 就是 testca/cacert.pem 的內容

var rootPEM = `-----BEGIN CERTIFICATE-----MIIDAjCCAeqgAwIBAgIJAL2faqa73yLvMA0GCSqGSIb3DQEBCwUAMDExIDAeBgNVBAMMF1RMU0dlblNlbGZTaWduZWR0Um9vdENBMQ0wCwYDVQQHDAQkJCQkMB4XDTE4MDIwNTA5Mzc0NVoXDTI4MDIwMzA5Mzc0NVowMTEgMB4GA1UEAwwXVExTR2VuU2VsZlNpZ25lZHRSb290Q0ExDTALBgNVBAcMBCQkJCQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9eO6Tam4XFDUbK9FAStAg29teYeKtt8WEJvKGB50xMfXO2pD0StsXhKrspXBYck0FwKIBsTLr97w7dSqa64z3U2V2BorogFzoEE4JH2sydYGAQqNAqezGx8VZnQVRyZEBifRPebR4WVD5GtXYe+MnSkHPIgsG0QG0SaiSfMl05dSJHoE9T9Kly9fH6yED88++OYjZZRGKOf2THpQlXJjF3iwCDLkwz9Z/kjmpK/rR0SEhtanf7bOgGs3OoFmX4DvmFJXoriVUC9jcj0Z4oX3Ld81XXyd4FJkpKvdKDhYkqcugFgERqdBeRDM+MA38YooKHZh0klL2EThNXJxM0r1vAgMBAAGjHTAbMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBCwUAA4IBAQBEqp0ON1A/pCKFztfKuzdW+9pauE8dl6Ij3++dt6AqW5QYFLOEFQwoMBOkGChGQDxHkakyaA0DfGe5JntMH0yYyZnr4kfs+AcY6P+2PfgrgVBqadhR6uAGOBaXDW7dlllqIJJ8NRInA/fTDYXMxBJbFrcj2cGIYVPvAbrosZ5L/YdAdVM76V8uuk8Hmmy5zRQj+gWt/jDkYWFrp0b6k3FBXvM7+nhqAIdyMjLioAdYwFpPglGj3xHXS5neWjyUDlAYISNe+PKMERSeDrptyDE+ljzl77hvvfZD9OPhXbDkAeVU/NaDwHG/G5HDVdNbg/FZ6ueevF34Xuzejm3lrdJm-----END CERTIFICATE-----`

也就是說,我們用準備好的 root CA 的內容產生了一個新的 http transport。

運行一下 go run client.go。成功!

This is an example server.

總結

一對 HTTPs client/server 程式中需要一個共同的 root CA。伺服器端需要該 root CA
建立的 CA/私密金鑰對。

這裡用的是 Go 語言來實現,其它的語言過程也類似。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.