在进行项目总结的时候,领导提出有关数据安全的问题。总结会议事后,本身查阅了一下资料,发现基于CA的TLS证书认证方案是一个很好的选择,虽然项目自己也有关于数据安全的处理,可是从远不及TLS的处理方式。git
本文只介绍tls的开发,采用go语言,不会涉及到太多专业的词语。github
初始目录以下:golang
grpc-tls/ ├── configs │ ├── cert # 存放证书相关的目录 ├── cmd
为了保证证书的可靠性和有效性,在这里可引入 CA 颁发的根证书的概念。CA就是专门用本身的私钥给别人进行签名的单位或者机构,其遵照 X.509 标准,即不管是客户端仍是服务端都是使用CA来签发证书。算法
根证书(root certificate)是属于根证书颁发机构(CA)的公钥证书。咱们能够经过验证 CA 的签名从而信任 CA ,任何人均可以获得 CA 的证书(含公钥),用以验证它所签发的证书(客户端、服务端)。shell
它包含了公钥和密钥。segmentfault
进入cert目录浏览器
openssl genrsa -out ca.key 2048
openssl genrsa
:生成RSA
私钥,命令的最后一个参数,将指定生成密钥的位数,若是没有指定,默认512openssl req -new -x509 -days 365 -key ca.key -out ca.pem
-x509
:证书文件格式为x509,目前TLS默认只支持这种格式的证书-days 365
:证书有效期1年-out ca.pem
:生成的私钥保存到ca.pem要填写的信息:tomcat
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 []:
grpc-tls/ ├── configs │ ├── cert # 存放证书相关的目录 │ ├── ca.key │ └── ca.pem ├── cmd
# openssl genrsa -out server.key 2048 或者 openssl ecparam -genkey -name secp384r1 -out server.key
openssl genrsa
:生成RSA
私钥,命令的最后一个参数,将指定生成密钥的位数,若是没有指定,默认512openssl ecparam
:生成ECC
私钥,命令为椭圆曲线密钥参数生成及操做,本文中ECC
曲线选择的是secp384r1
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 []:
使用CA的公钥对申请文件进行签名
openssl x509 -req -sha256 -CA ca.pem -CAkey ca.key -CAcreateserial -days 3650 -in server.csr -out server.pem
-sha256
:生成的证书里面使用sha256做为摘要算法grpc-tls/ ├── configs │ ├── cert # 存放证书相关的目录 │ ├── ca.key │ └── ca.pem │ ├── server.csr │ └── server.key │ └── server.pem ├── cmd
今生成的证书可用于浏览器、java、tomcat、golang等。
openssl ecparam -genkey -name secp384r1 -out client.key
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 []:
openssl x509 -req -sha256 -CA ca.pem -CAkey ca.key -CAcreateserial -days 3650 -in client.csr -out client.pem
该证书用于导入浏览器使用。
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:\Windows\System32\drivers\etc\hosts
添加一记录:
127.0.0.1 domain.com
测试完成以后记得手动将127.0.0.1 domain.com
从C:\Windows\System32\drivers\etc\hosts
里面删掉。
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
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