当前位置 博文首页 > janbar:创建并使用https证书

    janbar:创建并使用https证书

    作者:janbar 时间:2021-01-21 22:05

    目录
    • 前言
    • 产生证书
    • 测试https服务器
    • 用tls加密tcp连接
    • 总结

    前言

    https要比http更安全些,因此可以配置Nginx服务器使用证书,客户端就会去第三方平台校验证书。
    但是我们自己的服务器和客户端只是想要加个密而已,也没必要跑去第三方平台校验证书,省钱方便。
    因此研究了一下生成证书和使用证书的笔记。

    产生证书

    网上很多都是用openssl命令行去产生,有点麻烦,主要是不想记一堆命令,因此找到一个非常简单的项目。
    项目地址:https://github.com/michaelklishin/tls-gen,需要环境有python3、openssl、make这三个工具。
    使用方法cd tls-gen/basic & make CN=www.janbar.com,这样客户端必须用该域名进行访问,并且要带上对应证书。
    最终产生如下三个文件,testca/cacert.pem是客户端使用,server/cert.pem,server/key.pem是服务器使用。

    testca/
      cacert.pem
    
    server/
      cert.pem
      key.pem
    

    记得在c:\Windows\System32\drivers\etc\hosts增加127.0.0.1 www.janbar.com,准备证书源码文件cert.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如下:

    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效果如下,显示了运行目录下的文件列表:

    <pre>
    <a href="test.exe">test.exe</a>
    <a href="test.go">test.go</a>
    </pre>
    

    用tls加密tcp连接

    测试代码test_tcp.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效果如下:

    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连接没有任何加密,现在想想还是不安全。用上证书,起码会校验访问域名和证书等信息,多少回安全一些。
    以上都是用来测试等等,如果需要正式使用证书,还是去各大网站花钱申请吧。我一直用万网的免费证书,但是有效期只有一年额。