我通过阿里云申请的证书里面只有`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
}
```
但是我访问域名,中间会过很多路由器和一些网络设备,客户端只验证证书域名不太靠谱,中间人可以在这些网络设备上伪造域名解析到他们的IP服务器上。甚至他们也可以伪造一个相同IP,让客户端以为访问到正确的IP上。但是证书却是成对出现,服务器上有私钥,所以我想通过上面代码,在客户端检查获取的pem证书和服务器一模一样,这样才信任这次连接,我只是想知道这种方式靠不靠谱额。
#6
更多评论