我通过阿里云申请的证书里面只有`xx.pem`和`xx.key`这两个文件,我查找了很多证书相关的资料,客户端确认服务器证书貌似需要`ca.crt`这种CA证书,我没有这个。然后我查了下中间人攻击就是有人替换了证书让客户端以为证书没问题,但实际用的是中间人给的证书。
所以我尝试如下代码,不知道可不可以防止中间人攻击,我的客户端直接读取`xx.pem`文件和go库连接https服务器获取的证书内容进行比较,如果不一样则说明被篡改,终止当前连接。我不知道我这样做对不对,有没有大佬确认一下,或者有更好方案啊?
原始需求就是当只有`xx.pem`和`xx.key`服务器证书文件时,如何保证客户端连接是没有问题的?
```go
package main
import (
"bytes"
"crypto/tls"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
"io"
"net/http"
"os"
)
func main() {
err := getPem()
if err != nil {
panic(err)
}
err = httpGet()
if err != nil {
panic(err)
}
}
var (
pemRawCerts [][]byte // xx.pem读取的原始数据
errCheckPem = errors.New("check xx.pem error")
)
func getPem() error {
certPEMBlock, err := os.ReadFile(`xxx.pem`)
if err != nil {
return err
}
var certDERBlock *pem.Block
for {
certDERBlock, certPEMBlock = pem.Decode(certPEMBlock)
if certDERBlock == nil {
break
}
if certDERBlock.Type == "CERTIFICATE" {
tmp := make([]byte, len(certDERBlock.Bytes))
copy(tmp, certDERBlock.Bytes)
pemRawCerts = append(pemRawCerts, tmp)
}
}
return nil
}
func httpGet() error {
c := http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
VerifyPeerCertificate: func(data [][]byte, verifiedChains [][]*x509.Certificate) error {
if len(data) == len(pemRawCerts) {
for i := len(data) - 1; i >= 0; i-- {
if !bytes.Equal(data[i], pemRawCerts[i]) {
return errCheckPem
}
}
// 只有当证书的每一项都正确才确定当前连接没问题
return nil
}
return errCheckPem
},
},
},
}
resp, err := c.Get("https://xxx.com")
if err != nil {
return err
}
defer resp.Body.Close()
n, err := io.Copy(io.Discard, resp.Body)
fmt.Println(n)
return err
}
```
更多评论
虽然你申请得到的只有只有xx.pem和xx.key,但是并不代表没有ca证书。这里的ca是具有公信力的证书机构授权的根证书,已经被你的电脑或者手机默认安装,所以客户端直接相信,也就不需要你客户端去填写根证书。
而自建的证书,才需要客户端手动填写,或者手动选择相信,因为主机上没有找到你的根证书,压根不相信它。
#3