Go代碼打通HTTPs

TL;DR 手工創(chuàng)建CA證書鏈湿痢,手寫代碼打通HTTPs的兩端

HTTPs最近是一個重要的話題,同時也是一個有點難懂的話題扑庞。所以網(wǎng)上有大量的HTTPs/TLS/SSL的教程譬重。關(guān)于這些的原理,這里不做講解罐氨,有興趣的可以自行搜索臀规。

本文介紹一個自己創(chuàng)建證書,并編寫 Go 代碼實現(xiàn) client/server 兩端的過程栅隐。從實踐的角度幫助理解塔嬉。

構(gòu)建 CA 證書鏈

我們首先要創(chuàng)建 client/server 使用的證書。創(chuàng)建證書的方法有很多種:有不怕麻煩租悄,直接通過 openssl
創(chuàng)建的谨究,有通過 cfssl 創(chuàng)建的。這里要介紹的是我認為最簡單的一種:tls-gen

tls-gen是一個用 Python 編寫的泣棋、非常易用的工具胶哲。它定義了三種 profile。這里我們選擇最簡單的一種:一個根證書和一組證書外傅、私鑰對纪吮。

在 shell 里面執(zhí)行一下的命令:

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

就這樣,我們就為域名 www.mytestdomain.io 創(chuàng)建了一套證書萎胰。觀察一下當前路徑的內(nèi)容碾盟,我們會發(fā)現(xiàn)兩個新的目錄:testcaserver。前者里面存放了剛剛創(chuàng)建的根證書 (root CA)技竟,后者里面存放了我們之后的服務程序要用的的證書和私鑰冰肴。

testca/
  cacert.pem

server/
  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)
    }
}

可以看到我們創(chuàng)建了一個 HTTP 服務,這個服務監(jiān)聽 1443 端口并且只處理一個路徑 /hello搓扯。然后調(diào)用了下面這個函數(shù)來監(jiān)聽 1443 端口检痰。注意我們給出了之前創(chuàng)建的服務的證書和私鑰 - 這樣就保證了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

這是因為系統(tǒng)不知道如何來處理這個 self signed 證書公壤。

各個 OS 添加根證書的方法是不同的。對于 Linux 系統(tǒng) (以 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

上面的方法會把我們手工創(chuàng)建的 root CA
添加到系統(tǒng)所已知的列表里面。這樣一來慨飘,所有用該 root CA
創(chuàng)建的證書都可以被認證了确憨。

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

This is an example server.

另一種訪問方法

假如只是一個普通的用戶,沒有 root/sudo 權(quán)限瓤的,不就無法做上面的操作了嗎休弃?這種情況下還有另外一種做法: 把 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 的內(nèi)容

var rootPEM = `
-----BEGIN CERTIFICATE-----
MIIDAjCCAeqgAwIBAgIJAL2faqa73yLvMA0GCSqGSIb3DQEBCwUAMDExIDAeBgNV
BAMMF1RMU0dlblNlbGZTaWduZWR0Um9vdENBMQ0wCwYDVQQHDAQkJCQkMB4XDTE4
MDIwNTA5Mzc0NVoXDTI4MDIwMzA5Mzc0NVowMTEgMB4GA1UEAwwXVExTR2VuU2Vs
ZlNpZ25lZHRSb290Q0ExDTALBgNVBAcMBCQkJCQwggEiMA0GCSqGSIb3DQEBAQUA
A4IBDwAwggEKAoIBAQC9eO6Tam4XFDUbK9FAStAg29teYeKtt8WEJvKGB50xMfXO
2pD0StsXhKrspXBYck0FwKIBsTLr97w7dSqa64z3U2V2BorogFzoEE4JH2sydYGA
QqNAqezGx8VZnQVRyZEBifRPebR4WVD5GtXYe+MnSkHPIgsG0QG0SaiSfMl05dSJ
HoE9T9Kly9fH6yED88++OYjZZRGKOf2THpQlXJjF3iwCDLkwz9Z/kjmpK/rR0SEh
tanf7bOgGs3OoFmX4DvmFJXoriVUC9jcj0Z4oX3Ld81XXyd4FJkpKvdKDhYkqcug
FgERqdBeRDM+MA38YooKHZh0klL2EThNXJxM0r1vAgMBAAGjHTAbMAwGA1UdEwQF
MAMBAf8wCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBCwUAA4IBAQBEqp0ON1A/pCKF
ztfKuzdW+9pauE8dl6Ij3++dt6AqW5QYFLOEFQwoMBOkGChGQDxHkakyaA0DfGe5
JntMH0yYyZnr4kfs+AcY6P+2PfgrgVBqadhR6uAGOBaXDW7dlllqIJJ8NRInA/fT
DYXMxBJbFrcj2cGIYVPvAbrosZ5L/YdAdVM76V8uuk8Hmmy5zRQj+gWt/jDkYWFr
p0b6k3FBXvM7+nhqAIdyMjLioAdYwFpPglGj3xHXS5neWjyUDlAYISNe+PKMERSe
DrptyDE+ljzl77hvvfZD9OPhXbDkAeVU/NaDwHG/G5HDVdNbg/FZ6ueevF34Xuze
jm3lrdJm
-----END CERTIFICATE-----`

也就是說圈膏,我們用準備好的 root CA 的內(nèi)容產(chǎn)生了一個新的 http transport玫芦。

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

This is an example server.

總結(jié)

一對 HTTPs client/server 程序中需要一個共同的 root CA桥帆。服務器端需要該 root CA
創(chuàng)建的 CA/私鑰對。

這里用的是 Go 語言來實現(xiàn)慎皱,其它的語言過程也類似老虫。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市茫多,隨后出現(xiàn)的幾起案子祈匙,更是在濱河造成了極大的恐慌,老刑警劉巖天揖,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件夺欲,死亡現(xiàn)場離奇詭異,居然都是意外死亡今膊,警方通過查閱死者的電腦和手機些阅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來斑唬,“玉大人市埋,你說我怎么就攤上這事∷×酰” “怎么了缤谎?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長褐着。 經(jīng)常有香客問我坷澡,道長,這世上最難降的妖魔是什么含蓉? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任频敛,我火速辦了婚禮镣陕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘姻政。我一直安慰自己,他們只是感情好岂嗓,可當我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布汁展。 她就那樣靜靜地躺著,像睡著了一般厌殉。 火紅的嫁衣襯著肌膚如雪食绿。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天公罕,我揣著相機與錄音器紧,去河邊找鬼。 笑死楼眷,一個胖子當著我的面吹牛铲汪,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播罐柳,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼掌腰,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了张吉?” 一聲冷哼從身側(cè)響起齿梁,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎肮蛹,沒想到半個月后勺择,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡伦忠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年省核,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片昆码。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡芳撒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出未桥,到底是詐尸還是另有隱情笔刹,我是刑警寧澤,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布冬耿,位于F島的核電站舌菜,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏亦镶。R本人自食惡果不足惜日月,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一袱瓮、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧爱咬,春花似錦尺借、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蜂绎,卻和暖如春栅表,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背师枣。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工怪瓶, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人践美。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓洗贰,卻偏偏與公主長得像,于是被迫代替她去往敵國和親陨倡。 傳聞我的和親對象是個殘疾皇子哆姻,可洞房花燭夜當晚...
    茶點故事閱讀 42,834評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 服務器https配置 配置https操作說明文檔 1、查看服務器環(huán)境配置(tomcat和apache合并使用) 2...
    南京楊小兵閱讀 8,811評論 0 9
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理玫膀,服務發(fā)現(xiàn)矛缨,斷路器,智...
    卡卡羅2017閱讀 134,600評論 18 139
  • 1.明確https域名帖旨,如:tomcat.loc箕昭,生成證書時使用 2.創(chuàng)建證書目錄 //進入tmp目錄 cd /h...
    _伽藍寺聽雨聲閱讀 1,998評論 0 6
  • 六月,去了一趟西安解阅,站在古都的城墻下落竹,總難免會想起過去的那些歷史,想起在這個古城里生活過的那些文人墨客货抄。后來述召,又去...
    西伯利亞百合閱讀 411評論 1 0
  • 星耀小學一年一班趙東洋 2018年1月4日 星期四 晴 今天早上,我剛起身蟹地,寶貝連忙說:“媽媽积暖,今天...
    趙東洋閱讀 254評論 1 1