zoukankan      html  css  js  c++  java
  • TLS示例开发-golang版本

    前言

    在进行项目总结的时候,领导提出有关数据安全的问题。总结会议过后,自己查阅了一下资料,发现基于CA的TLS证书认证方案是一个很好的选择,虽然项目本身也有关于数据安全的处理,但是从远不及TLS的处理方式。

    本文只介绍tls的开发,采用go语言,不会涉及到太多专业的词语。


    制作自签名证书

    初始目录如下:

    grpc-tls/
    ├── configs
    │   ├── cert # 存放证书相关的目录
    ├── cmd
    

    CA

    为了保证证书的可靠性和有效性,在这里可引入 CA 颁发的根证书的概念。CA就是专门用自己的私钥给别人进行签名的单位或者机构,其遵守 X.509 标准,即无论是客户端还是服务端都是使用CA来签发证书。

    根证书

    根证书(root certificate)是属于根证书颁发机构(CA)的公钥证书。我们可以通过验证 CA 的签名从而信任 CA ,任何人都可以得到 CA 的证书(含公钥),用以验证它所签发的证书(客户端、服务端)。

    它包含了公钥和密钥。

    CA公钥

    进入cert目录

    openssl genrsa -out ca.key 2048
    
    • openssl genrsa:生成RSA私钥,命令的最后一个参数,将指定生成密钥的位数,如果没有指定,默认512

    CA秘钥(证书)

    openssl req -new -x509 -days 365 -key ca.key -out ca.pem
    
    • -x509:证书文件格式为x509,目前TLS默认只支持这种格式的证书
    • -days 365:证书有效期1年
    • -out ca.pem:生成的私钥保存到ca.pem

    要填写的信息:

    Country Name (2 letter code) [XX]:
    State or Province Name (full name) []:
    Locality Name (eg, city) [Default City]:
    Organization Name (eg, company) [Default Company Ltd]:
    Organizational Unit Name (eg, section) []:
    Common Name (eg, your name or your server's hostname) []:ca.com
    Email Address []:
    
    • 生成的过程中会要求填一些信息,除了Common Name要取一个容易区分的名字之外,其它都可以随便填写,我们在这里将它填为ca.com.

    目录

    grpc-tls/
    ├── configs
    │   ├── cert # 存放证书相关的目录
    │   	├── ca.key
    │   	└── ca.pem
    ├── cmd
    

    服务器证书相关

    服务器key

    # openssl genrsa -out server.key 2048
    或者
    openssl ecparam -genkey -name secp384r1 -out server.key
    
    • openssl genrsa:生成RSA私钥,命令的最后一个参数,将指定生成密钥的位数,如果没有指定,默认512
    • openssl ecparam:生成ECC私钥,命令为椭圆曲线密钥参数生成及操作,本文中ECC曲线选择的是secp384r1

    生成 CSR(证书申请文件)

    CSR 是**Cerificate Signing Request **的英文缩写,为证书申请文件,在服务器私钥的基础上加上一些申请人的属性信息,比如我是谁,来自哪里,名字叫什么,证书适用于什么场景等的信息,然后带上进行的签名,发给CA(私下安全的方式发送),带上自己签名的目的是为了防止别人篡改文件。

    openssl req -new -key server.key -out server.csr
    

    要填写的信息:

    Country Name (2 letter code) [AU]:
    State or Province Name (full name) [Some-State]:
    Locality Name (eg, city) []:
    Organization Name (eg, company) [Internet Widgits Pty Ltd]:
    Organizational Unit Name (eg, section) []:
    Common Name (e.g. server FQDN or YOUR name) []:domain.com
    Email Address []:
    
    Please enter the following 'extra' attributes
    to be sent with your certificate request
    A challenge password []:123456
    An optional company name []:
    
    • 生成的过程中会要求填一些信息,除了Common Name要取一个容易区分的名字之外,其它都可以随便填写,我们在这里将它填为domain.com;
    • 密码也是建议填写;
    • 注意和ca证书的不同。

    基于 CA 签发

    使用CA的公钥对申请文件进行签名

    openssl x509 -req -sha256 -CA ca.pem -CAkey ca.key -CAcreateserial -days 3650 -in server.csr -out server.pem
    
    • -sha256:生成的证书里面使用sha256作为摘要算法
    • 由于需要往生成的证书里写入签名者的信息,所以这里需要ca.pem,因为只有这里有CA的描述信息,ca.key里面只有公钥的信息。

    目录

    grpc-tls/
    ├── configs
    │   ├── cert # 存放证书相关的目录
    │   	├── ca.key
    │   	└── ca.pem
    │   	├── server.csr
    │   	└── server.key
    │   	└── server.pem
    ├── cmd
    

    客户端证书相关

    此生成的证书可用于浏览器、java、tomcat、golang等。

    客户端key

    openssl ecparam -genkey -name secp384r1 -out client.key
    

    生成CSR(证书申请书)

    openssl req -new -key client.key -out client.csr
    

    要填写的信息:

    Country Name (2 letter code) [AU]:
    State or Province Name (full name) [Some-State]:
    Locality Name (eg, city) []:
    Organization Name (eg, company) [Internet Widgits Pty Ltd]:
    Organizational Unit Name (eg, section) []:
    Common Name (e.g. server FQDN or YOUR name) []:domain.com
    Email Address []:
    
    Please enter the following 'extra' attributes
    to be sent with your certificate request
    A challenge password []:123456
    An optional company name []:
    
    • Common Name要取一个容易区分的名字之外,填为domain.com,和服务器的CSR保持一致;
    • 密码也是建议填写;
    • 注意和ca证书的不同。

    基于CA签发

    openssl x509 -req -sha256 -CA ca.pem -CAkey ca.key -CAcreateserial -days 3650 -in client.csr -out client.pem
    

    生成客户端p12格式根证书

    该证书用于导入浏览器使用。

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

    目录

    grpc-tls/
    ├── configs
    │   ├── cert # 存放证书相关的目录
    │   	├── ca.key
    │   	└── ca.pem # 导入浏览器使用
    │   	├── server.csr
    │   	└── server.key
    │   	└── server.pem
    │   	├── client.csr
    │   	└── client.key
    │   	└── client.pem
    │   	└── client.p12 # 导入浏览器使用
    ├── cmd
    

    证书如何验证

    下面以浏览器为例,说明证书的验证过程:

    • 在TLS握手的过程中,浏览器得到了网站的证书(.p12)

    • 打开证书,查看是哪个CA签名的这个证书(.p12)

    • 在自己信任的CA库中,找相应CA的证书(ca.pem),

    • 用CA证书里面的公钥解密网站证书上的签名,取出网站证书的校验码(指纹),然后用CA证书中摘要算法(比如sha256)算出出网站证书的校验码,如果校验码和签名中的校验码对的上,说明这个证书是合法的,且没被人篡改过

    • 读出里面的CN,对于网站的证书,里面一般包含的是域名

    • 检查里面的域名和自己访问网站的域名对不对的上,对的上的话,就说明这个证书确实是颁发给这个网站的

    • 到此为止检查通过

    如果浏览器发现证书有问题,一般是证书里面的签名者不是浏览器认为值得信任的CA,浏览器就会给出警告页面,这时候需要谨慎,有可能证书被掉包了。如访问12306网站,由于12306的证书是自己签的名,并且浏览器不认为12306是受信的CA,所以就会给警告,但是一旦你把12306的根证书安装到了你的浏览器中,那么下次就不会警告了,因为你配置了浏览器让它相信12306是一个受信的CA。


    在浏览器中导入证书

    导入证书

    • 详细步骤百度即可....

    • 个人导入client.p12证书

    • 受信任的根证书颁发机构导入ca.pem证书

    修改域名

    ca.pem这个证书是发给domain.com的,而不是127.0.0.1,所以在C:WindowsSystem32driversetchosts添加一记录:

    127.0.0.1   domain.com
    

    测试完成之后记得手动将127.0.0.1 domain.comC:WindowsSystem32driversetchosts里面删掉。


    golang服务端

    目录

    grpc-tls/
    ├── configs
    │   ├── cert # 存放证书相关的目录
    │   	├── ca.key
    │   	└── ca.pem # 导入浏览器使用
    │   	├── server.csr
    │   	└── server.key
    │   	└── server.pem
    │   	├── client.csr
    │   	└── client.key
    │   	└── client.pem
    │   	└── client.p12 # 导入浏览器使用
    ├── cmd
    │   ├── main.go
    

    main.go

    package main
    
    import (
    	"crypto/tls"
    	"crypto/x509"
    	"github.com/gin-gonic/gin"
    	"io/ioutil"
    	"log"
    	"net/http"
    	"time"
    )
    
    func main() {
    	router := gin.Default()
    	router.GET("/test", func(c *gin.Context) {
    		c.JSON(200, gin.H{
    			"message": "test",
    		})
    	})
    
    	// 启动https方式访问
    	cert, err := tls.LoadX509KeyPair("./configs/cert/server.pem", "./configs/cert/server.key")
    	if err != nil {
    		log.Fatalf("tls.LoadX509KeyPair err: %v", err)
    	}
    	certPool := x509.NewCertPool()
    	ca, err := ioutil.ReadFile("./configs/cert/ca.pem")
    	if err != nil {
    		log.Fatalf("ioutil.ReadFile err: %v", err)
    	}
    	if ok := certPool.AppendCertsFromPEM(ca); !ok {
    		log.Fatalf("certPool.AppendCertsFromPEM err")
    	}
    	ReadTimeout := time.Duration(60) * time.Second
    	WriteTimeout := time.Duration(60) * time.Second
    
    	s := &http.Server{
    		Addr:          ":8090",
    		Handler:        router,
    		ReadTimeout:    ReadTimeout,
    		WriteTimeout:   WriteTimeout,
    		MaxHeaderBytes: 1 << 20,
    		TLSConfig:&tls.Config{
    			Certificates: []tls.Certificate{cert},
    			MinVersion: tls.VersionTLS12,
    			ClientAuth:   tls.RequireAndVerifyClientCert,
    			ClientCAs:    certPool,
    		},
    	}
    
    	s.ListenAndServeTLS("./configs/cert/server.pem","./configs/cert/server.key")
    }
    
    

    测试

    在浏览器输入https://domain.com:8090/test


    参考

    SSL/TLS及证书概述

    带入gRPC:TLS 证书认证

  • 相关阅读:
    CodeForces 706C Hard problem
    CodeForces 706A Beru-taxi
    CodeForces 706B Interesting drink
    CodeForces 706E Working routine
    CodeForces 706D Vasiliy's Multiset
    CodeForces 703B Mishka and trip
    CodeForces 703C Chris and Road
    POJ 1835 宇航员
    HDU 4907 Task schedule
    HDU 4911 Inversion
  • 原文地址:https://www.cnblogs.com/dust90/p/11207219.html
Copyright © 2011-2022 走看看