1. 程式人生 > >建立並使用https證書

建立並使用https證書

[toc] ## 前言 > https要比http更安全些,因此可以配置Nginx伺服器使用證書,客戶端就會去第三方平臺校驗證書。 > 但是我們自己的伺服器和客戶端只是想要加個密而已,也沒必要跑去第三方平臺校驗證書,省錢方便。 > 因此研究了一下生成證書和使用證書的筆記。 ## 產生證書 > 網上很多都是用openssl命令列去產生,有點麻煩,主要是不想記一堆命令,因此找到一個非常簡單的專案。 > 專案地址:,需要環境有`python3、openssl、make`這三個工具。 > 使用方法`cd tls-gen/basic & make CN=www.janbar.com`,這樣客戶端必須用該域名進行訪問,並且要帶上對應證書。 > 最終產生如下三個檔案,`testca/cacert.pem`是客戶端使用,`server/cert.pem,server/key.pem`是伺服器使用。 ```sh testca/ cacert.pem server/ cert.pem key.pem ``` >
記得在`c:\Windows\System32\drivers\etc\hosts`增加`127.0.0.1 www.janbar.com`,準備證書原始碼檔案`cert.go`,內容如下: ```go var ( certPEMBlock = []byte(`-----BEGIN CERTIFICATE----- MIIDfjCCAmagAwIBAgIBATANBgkqhkiG9w0BAQsFADAxMSAwHgYDVQQDDBdUTFNH ZW5TZWxmU2lnbmVkdFJvb3RDQTENMAsGA1UEBwwEJCQkJDAeFw0yMTAxMjExMDEx MjJaFw0zMTAxMTkxMDExMjJaMCoxFzAVBgNVBAMMDnd3dy5qYW5iYXIuY29tMQ8w DQYDVQQKDAZzZXJ2ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDj pGglwTB/B1N07ZhwaP3erxDZDYhtDqir7fiuZQxgmWzQ5UeU7gp5ntu8bLXpFmVS s7si0WyOKbGoPi8Q/cvkZix3zkClAvS7vM2zW+0qa3Fp4dYRg42cjYAgenfpC0M5 fKHhnBKjzWFOiTOyJIPcNpvhAcV9dvQIdgX64g/+M2J3pMK2+tU5Z49Nc1KqyUS/ /zFo4C+HAk7Wbkc3Kgx8t4OZo0ddTdmLsPfRIU3hxqehRxhk7OccHBBb6JOVSF21 3h6kWwauN9djiOixpsS3jr1SVEGrhZk6zaOtZ+MSOg410pr3u79kdIuCYGNhvdDW soyNBNCFGOP/kj7dO5p/AgMBAAGjgacwgaQwCQYDVR0TBAIwADALBgNVHQ8EBAMC BaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwNQYDVR0RBC4wLIIOd3d3LmphbmJhci5j b22CD0RFU0tUT1AtQ1YxUUhPRIIJbG9jYWxob3N0MB0GA1UdDgQWBBSUjXz9K9NO tJJs+YXHVBUBG5RPEzAfBgNVHSMEGDAWgBRFxl2tSPMYhPZ+Pf6O1HiZ65yJzzAN BgkqhkiG9w0BAQsFAAOCAQEALxVtveN3LI1vi4uiaId6O87OjirugSD1xSkD7MFj aBb2u0+a/ziiNXeLCtxNxSb7HTknd/6SuTdgHzq1sCczk0BcV3FfEjNw3Y4sz9JO 0CBFnpgIvqFoA+rJEIiUwhyOkCh/aIVT8VMGm3gAHAeMhrYd4iF590+P1vgXTrvr 6T3FKojng3IgXxYzVUcia/UNEfY8U6f6yThC22kcThK/OeywpLB+NCm9/wt7sQUZ T8BEfhz0AKHFIih8wq5DD87Vc6fHkUBX6NBKmstm5X5smQTjJGd985fx1Rdka5ro o0IH6DYd8PjN0asvEb1RG5viSpcpXc5IFh7mNzmxaA7Ygw== -----END CERTIFICATE-----`) keyPEMBlock = []byte(`-----BEGIN PRIVATE KEY----- MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDjpGglwTB/B1N0 7ZhwaP3erxDZDYhtDqir7fiuZQxgmWzQ5UeU7gp5ntu8bLXpFmVSs7si0WyOKbGo Pi8Q/cvkZix3zkClAvS7vM2zW+0qa3Fp4dYRg42cjYAgenfpC0M5fKHhnBKjzWFO iTOyJIPcNpvhAcV9dvQIdgX64g/+M2J3pMK2+tU5Z49Nc1KqyUS//zFo4C+HAk7W bkc3Kgx8t4OZo0ddTdmLsPfRIU3hxqehRxhk7OccHBBb6JOVSF213h6kWwauN9dj iOixpsS3jr1SVEGrhZk6zaOtZ+MSOg410pr3u79kdIuCYGNhvdDWsoyNBNCFGOP/ kj7dO5p/AgMBAAECggEAIG96j3aZbGAk2hJImCu9kI8tPWAaQj/GdMjxmBe5zcHO qW0h5+yK/Y1PDegHe3C/eys0zN8+MntqXuiNWERxWtfcGi3/NAPZzy41uQquHk80 17tf/xrZgKcAzJ/mmgQKzhQeFMFiPoizBrex7/4X87asO0E/XIMoflQiwf6X/MYc w/2ExWGoSxucsZs1J7HuBWp10G26t7yZEEFy+IjS8aleNnBm0vBgSZ2R/cqIpqTD hvfnM/Xv8ERVMlj+pzac+qzAyRJHgEkYdOzwy9+7v9bT3fv99I+jHJjo5qMu4/vM s2QMypO2ams4ClbB6bgcq1Bt8/WATXoS4hbyCNDNYQKBgQDzBnJKQ3Iqc7rqYHDY romxqwyeHsi5sCXCsA806drQBIX+n3MhJ5UcveDNW6QtNPX8/v8JWLU+yR64zatf Qz5YFBLcF2NYvkO3z5vrvCmRYZaAbmMv1I+RKTWL2UDi1JBTteTG5g9BLIPMGIuz WNVnrAG61IsHLnBzUvMuLxJn6QKBgQDvy7aW22yocsZBUlZ0bDxY7OieEQbCuafx ncbGlSRfqCkwU1MKifZHFbLlxlklr+bQJRDlN2RYtLBSKeU65PK2zm7G6hgRcBMG 52SiW59QoGmiP5DmZj4ILAV9/SmlTRsnB6q2OXdkAZ06vNI2oPMznSUiFyB2MJiH lrG0MGnWJwKBgQDt5oKdNjcdXZs9ctklFH8QYIyCgUonlErysdzBBKhB+BufrUFL 1G7A6xOUlEA8TNr9JjZNVPxgEQu1BwjawX3XRRdNQsvrBJ5P4rkU5GagvbJR2T3Z hbBg/sE/PJarNkBu4eGp325Rc501f1XKZIzL5vLujL/ocMp96lbKACR5eQKBgDTF 2WYz3iLoN3dyvnIay+EqKjt3Ncyu/SXweimD8yBWKtJm1BSyrg+Q1/E3iLEBmENg lOpNGXloMpGyhK9EaaIPplOCe0+DIbzYOc59aX9d/kFlyebaw3Ya8g57I6osYPhi +I/n772DmW2u1niNTVijkeOBwXQhV8AnSu6D5RbrAoGBAOycwo6VQGUNkwQW6e02 32TdC9C66Ky8tB/SWusu6fGD6hpHBA15T/saOuZ6WE0ir7VGyAr1P04mYebcZ31P B14WxQ1BhT6MGdd6DK+kG+gIfT38sSwy/sHIpbM+KcijmX2jJ1qf1O8TJHlvXMdx fuPIaJgJmNZtnQtAo2f+XVWp -----END PRIVATE KEY-----`) rootPEM = []byte(`-----BEGIN CERTIFICATE----- MIIDUDCCAjigAwIBAgIUI8rwLlo1JMFnSeuNOdR7qf1vkU4wDQYJKoZIhvcNAQEL BQAwMTEgMB4GA1UEAwwXVExTR2VuU2VsZlNpZ25lZHRSb290Q0ExDTALBgNVBAcM BCQkJCQwHhcNMjEwMTIxMTAxMTIyWhcNMzEwMTE5MTAxMTIyWjAxMSAwHgYDVQQD DBdUTFNHZW5TZWxmU2lnbmVkdFJvb3RDQTENMAsGA1UEBwwEJCQkJDCCASIwDQYJ KoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6NWvQP5lDgIDh5IC/BDHm1egEP3BG1 Mqu0rO0505Vp5Y1/oc3OGqi3cJLcJ0JOjq4Y6pjTmqlf0zLG1LgRw96bJid0LI2O iCDHCkdu3efU3aWxXgGxRBLPe8g7JHUSoIGsERrjqxsplQ38z6n+Yzbndjixz11r MCeQXS+FZeHFdkqEiy7DDrDa1OxthH8lFjPqcxBC5Dz4OO7eNhwLtru9sMSYYvOL jO6TmpHsd6OHUDVFFfaXSxHGeRFKDm9cYqKmO4oexm4QFAtoDaWCDXcAnS8hi7ze wAGhVPTRZp/lXuCqwsAAjU40vb8Pqq5zuY05eCYINwPYY5S1OMNTfJMCAwEAAaNg MF4wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBRFxl2tSPMYhPZ+Pf6O1HiZ65yJzzAf BgNVHSMEGDAWgBRFxl2tSPMYhPZ+Pf6O1HiZ65yJzzAPBgNVHRMBAf8EBTADAQH/ MA0GCSqGSIb3DQEBCwUAA4IBAQA03g3/AC3ylUjATzhxyglarRNrneZKM96KFm3c z99HzxBxX71hKBF6kV6GKdKQkl4Ocx6HLiHiIWviTFr0qNVNcafrdDwWa9dRg5da xKOOE9XoLYHWDmDaKgAIz4x5tDUDhAT4u7hkHQACz4TMlQG6L2uXPI0IiTv5185w vgNNpx2V3d9rlvq6AOWjhSrZ9rfuSnt3UbRjKmbZAGcaFb3Gqr7MdIZuYOB9CN7H o0wKNxKk00o7jav298tHinDdKvwYdAf8IgkEaHgBeFsPfNy8VGe4XWNdVT7HkzpO PHM7SBK+cEpKnylKkEdKb9ubSCe8NA4RpuKbeo36IS6Bcfmr -----END CERTIFICATE-----`) ) ``` ## 測試https伺服器 >
測試程式碼檔案`test_https.go`如下: ```go package main import ( "crypto/tls" "crypto/x509" "io" "net/http" "os" "time" ) func main() { http.Handle("/", http.FileServer(http.Dir("."))) go func() { cf, err := tls.X509KeyPair(certPEMBlock, keyPEMBlock) if err != nil { panic(err) } err = (&http.Server{TLSConfig: &tls.Config{ Certificates: []tls.Certificate{cf}, }}).ListenAndServeTLS("", "") if err != nil { panic(err) } }() time.Sleep(time.Second) // 上面是http伺服器的執行 // 下面是http客服端訪問 roots := x509.NewCertPool() ok := roots.AppendCertsFromPEM(rootPEM) if !ok { panic("failed to parse root certificate") } client := &http.Client{Transport: &http.Transport{ TLSClientConfig: &tls.Config{RootCAs: roots}, }} req, err := http.NewRequest(http.MethodGet, "https://www.janbar.com", nil) if err != nil { panic(err) } resp, err := client.Do(req) if err != nil { panic(err) } io.Copy(os.Stdout, resp.Body) resp.Body.Close() } ``` >
執行`go run test_https.go cert.go`效果如下,顯示了執行目錄下的檔案列表: ```go
test.exe
test.go
``` ## 用tls加密tcp連線 > 測試程式碼`test_tcp.go`檔案,原始碼如下: ```go package main import ( "crypto/tls" "crypto/x509" "fmt" "net" "time" ) func main() { addr := "www.janbar.com:8080" go func() { err := tcpServer(addr) if err != nil { panic(err) } }() time.Sleep(time.Second) err := tcpClient(addr) if err != nil { panic(err) } } func tcpServer(addr string) error { cf, err := tls.X509KeyPair(certPEMBlock, keyPEMBlock) if err != nil { return err } s, err := tls.Listen("tcp", addr, &tls.Config{Certificates: []tls.Certificate{cf}}) if err != nil { return err } defer s.Close() client := func(c net.Conn) error { tNow := time.Now().String() buf := make([]byte, len(tNow)) n, err := c.Read(buf) if err != nil { return err } fmt.Printf("server [%s]\n", buf[:n]) _, err = c.Write([]byte(tNow)) return err } for { l, err := s.Accept() if err != nil { return err } go func(c net.Conn) { defer c.Close() if err := client(c); err != nil { fmt.Println(err) } }(l) } } func tcpClient(addr string) error { roots := x509.NewCertPool() ok := roots.AppendCertsFromPEM(rootPEM) if !ok { panic("failed to parse root certificate") } c, err := tls.Dial("tcp", addr, &tls.Config{RootCAs: roots}) if err != nil { return err } defer c.Close() tNow := time.Now().String() c.Write([]byte(tNow)) buf := make([]byte, len(tNow)) n, err := c.Read(buf) if err != nil { return err } fmt.Printf("client [%s]\n", buf[:n]) return nil } ``` > 執行`go run test_tcp.go cert.go`效果如下: ```go server [2021-01-21 21:09:51.7942154 +0800 CST m=+1.011929701] client [2021-01-21 21:09:51.7852425 +0800 CST m=+1.002956801] ``` ## 總結 > 以前使用的tcp連線沒有任何加密,現在想想還是不安全。用上證書,起碼會校驗訪問域名和證書等資訊,多少回安全一些。 > 以上都是用來測試等等,如果需要正式使用證書,還是去各大網站花錢申請吧。我一直用萬網的免費證書,但是有效期只有一