证书与https
为什么要使用证书
非对称加密存在公钥分发困难的问题
- 直接传递公钥,容易被截取
- 放到固定的位置,容易被替换
解决办法
引入第三方认证机构,CA(Certificate Authority)
CA机构是一系列具有社会公信力的机构的总称,它们负责为厂商提供数字证书(有公钥),从而解决公钥分发困难的问题
证书使用流程
https
http:应用层协议,标准协议
https:不是标准协议,http
+ssl
(security socket layer
)
以访问百度为例
- 百度首先在本地生成秘钥对(也可以由CA帮忙生成)
- 将公钥发送给CA机构(CA也有自己的公钥私钥)
- CA对百度的公钥进行处理,生成输入百度数字证书(CA根证书签发的,CA的私钥)。 服务器得到证书
- 客户浏览器访问百度,百度会把自己的证书发送会浏览器
- 浏览器会认证这个证书是否有效(操作系统内置了各大主流CA机构的根证书)
- 如果证书有效:
- 访问ip与证书一直
- 证书在有效期内
….
百度得到证明。
- 如果认证无效,Not Secure,当然了用户也可以选择继续浏览
如果证书有效,客户的浏览器可以得到服务器的(公钥:在证书内),接下来交互就开始使用对称加密。
- 浏览器生成对称秘钥,使用服务器的公钥加密,发送给服务器。
- 服务器使用私钥解开秘钥。使用秘钥加密数据做应答。
- 接下来所有的数据交互都使用对称加密进行
Linux下生成自签名证书
-
生成私钥
openssl genrsa -out server.key 1024 //不加密
或
openssl genrsa -des3 -out server.key 1024 //使用des3加密
-
使用私钥生成csr(证书签名请求)
openssl req -new -key server.key -out server.csr
查看csr详情:
openssl req -in server.csr -text
-
生成自签名证书(用自己的key给自己的csr签名)
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
查看自签名证书:
openssl x509 -in server.crt -text
go语言简单实现https服务器和客户端
服务器
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("hello world"))
})
fmt.Println("服务器启动...")
// func ListenAndServeTLS(addr, certFile, keyFile string, handler Handler) error
err := http.ListenAndServeTLS(":8082", "server.crt", "server.key", nil)
if err != nil {
fmt.Println("err :", err)
}
}
客户端
注意:
client.Get()
里的URL必须是生成csr时Common Name (e.g. server FQDN or YOUR name) []:
后面你输入的内容,这里我输入了www.it.com
,还需要注意的是,要把此项添加到/etc/hosts
中,打开后添加127.0.0.1 www.it.com
- 我们需要自己校验证书是否有效,这就需要我们把服务器证书的根证书添加到根证书列表中(我们是自签名证书,”server.crt“就是当前服务器的根证书),否则会报错(
err: Get https://www.it.com:8082: x509: certificate signed by unknown authority
)。
func main() {
//需要告诉client,我们认可ca
// 1. 读取证书
caCert, err := ioutil.ReadFile("server.crt")
if err != nil {
fmt.Println("read server.crt failed : ", err)
return
}
// 2. 创建ca池,ca pool
//返回一个新的,空的ca池
capool := x509.NewCertPool()
// 3. 将我们认可的根证书,添加至ca pool
ok := capool.AppendCertsFromPEM(caCert)
if !ok {
fmt.Println("添加ca 池失败!")
return
}
// 4. 创建tls结构,填入pool(TLS相当于是SSL的后续版本)
config := tls.Config{
//将拼凑好的ca池配置到tls配置结构中
RootCAs: capool,
}
// 5. 创建client 通道
//创建http客户端
client := http.Client{
Transport: &http.Transport{
TLSClientConfig: &config,
},
}
//发起get请求
response, err := client.Get("https://www.it.com:8082")
if err != nil {
fmt.Println("err :", err)
return
}
//获取body数据
body, err := ioutil.ReadAll(response.Body)
if err != nil {
fmt.Println("err :", err)
return
}
defer response.Body.Close()
fmt.Printf("body: %s\n", body)
}