2017-05-31 30 views
0

如何在go http客戶端內禁用通用名稱驗證。我正在與一個通用的CA進行相互的TLS,因此通用的名稱驗證沒有任何意義。禁用通用名稱驗證 - Go HTTP客戶端

的TLS docs說,

// ServerName is used to verify the hostname on the returned 
// certificates unless InsecureSkipVerify is given. It is also included 
// in the client's handshake to support virtual hosting unless it is 
// an IP address. 
ServerName string 

我不想做InsecureSkipVerify但我不想要驗證的通用名稱。

回答

1

您可以通過一個tls.Config結構與您自己的VerifyPeerCertificate函數,然後您將自己檢查證書。

VerifyPeerCertificate func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error

如果正常校驗失敗,那麼握手將 前中止考慮這個回調。如果正常驗證被 設置爲InsecureSkipVerify禁用,則將考慮此回調,但 verifiedChains參數始終爲零。

有關如何驗證證書的示例,您可以查看here。如果你看看here,你會發現即使這個驗證過程的一部分包括檢查主機名,但是幸運的是,如果它被設置爲空字符串,你會看到它是skips it

所以,基本上你寫你自己VerifyPeerCertificate功能,轉換rawCerts [][]byte,我認爲會是這個樣子:

customVerify := func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { 
    roots := x509.NewCertPool() 
    for _, rawCert := range rawCerts { 
     cert, _ := x509.ParseCertificate(rawCert) 
     roots.AddCert(cert) 
    } 
    opts := x509.VerifyOptions{ 
     Roots: roots, 
    } 
    _, err := cert.Verify(opts) 
    return err 
} 

conf := tls.Config{ 
    //... 
    VerifyPeerCertificate: customVerify, 
} 
+0

不執行通用名稱驗證是否正常?或者,我的使用案例是一個邊緣案例 – frankgreco

+3

IMO它確實沒有意義驗證證書,但不是通用名稱。在這一點上,我可以通過任何域名有效證書,你會檢查並說「是的,看起來確定」,所以你沒有得到任何實際的安全。 – dave

+0

其中是來自'_,err:= cert.Verify(opts)'的'cert' – frankgreco

0

普通HTTPS POST這樣

pool := x509.NewCertPool() 
caStr, err := ioutil.ReadFile(serverCAFile) 
if err != nil { 
    return nil, fmt.Errorf("read server ca file fail") 
} 
pool.AppendCertsFromPEM(caStr) 
tr := &http.Transport{ 
    TLSClientConfig: &tls.Config{ 
     RootCAs: pool, 
    }, 
} 

client := &http.Client{Transport: tr} 
client.Post(url, bodyType, body) 

但是,如果您的網址是使用ip(例如:https://127.0.0.1:8080/api/test)或者你的URL不符合證書的通用名稱,而你只想忽略證書的通用名稱檢查,應該這樣做

pool := x509.NewCertPool() 
caStr, err := ioutil.ReadFile(serverCAFile) 
if err != nil { 
    return nil, fmt.Errorf("read server ca file fail") 
} 
block, _ := pem.Decode(caStr) 
if block == nil { 
    return nil, fmt.Errorf("Decode ca file fail") 
} 
if block.Type != "CERTIFICATE" || len(block.Headers) != 0 { 
    return nil, fmt.Errorf("Decode ca block file fail") 
} 

cert, err := x509.ParseCertificate(block.Bytes) 
if err != nil { 
    return nil, fmt.Errorf("ParseCertificate ca block file fail") 
} 

pool.AddCert(cert) 

tr := &http.Transport{ 
    TLSClientConfig: &tls.Config{ 
     RootCAs: pool, 
     ServerName: cert.Subject.CommonName, //manual set ServerName 
    }, 
} 

client := &http.Client{Transport: tr} 
client.Post(url, bodyType, body)