在進行項目總結的時候,領導提出有關數據安全的問題。總結會議事後,本身查閱了一下資料,發現基於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