强制HttpClient信任单个证书

你能强迫HttpClient只信任一个证书吗?

我知道你可以这样做:

WebRequestHandler handler = new WebRequestHandler(); X509Certificate2 certificate = GetMyX509Certificate(); handler.ClientCertificates.Add(certificate); HttpClient client = new HttpClient(handler); 

但是这会迫使它只信任单个证书,还是会信任证书和所有证书fx。 GlobalSign可以validation吗?

基本上我想确保它只能是我的客户正在与之交谈的服务器/证书。

你能强迫HttpClient只信任一个证书吗? …基本上我想确保它只能是我的客户正在与之交谈的服务器/证书。

是。 但什么类型的证书? 服务器还是CA? 以下两个例子。

此外,在服务器的情况下,固定公钥而不是证书可能更好。 这是因为像谷歌这样的一些组织每30天左右轮换一次服务器证书,以便为移动客户端保持较小的CRL。 但是,组织将重新认证相同的公钥。


以下是将CA从特定CA用于SSL连接的固定CA的示例。 它不需要将证书放在证书库中。 您可以在应用中携带CA.

 static bool VerifyServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { try { String CA_FILE = "ca-cert.der"; X509Certificate2 ca = new X509Certificate2(CA_FILE); X509Chain chain2 = new X509Chain(); chain2.ChainPolicy.ExtraStore.Add(ca); // Check all properties (NoFlag is correct) chain2.ChainPolicy.VerificationFlags = X509VerificationFlags.NoFlag; // This setup does not have revocation information chain2.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; // Build the chain chain2.Build(new X509Certificate2(certificate)); // Are there any failures from building the chain? if (chain2.ChainStatus.Length == 0) return false; // If there is a status, verify the status is NoError bool result = chain2.ChainStatus[0].Status == X509ChainStatusFlags.NoError; Debug.Assert(result == true); return result; } catch (Exception ex) { Console.WriteLine(ex); } return false; } 

没有想出如何使用这个链(上面的chain2 ),这样就不需要回调了。 也就是说,将它安装在ssl套接字上,连接将“正常工作”。

而且我还没弄清楚如何安装它以便将其传递给回调。 也就是说,我必须为每次调用回调构建链,因为我的chain2没有作为chain传递给函数。


以下是从OWASP的证书和公钥固定中固定服务器证书的示例。 它不需要将证书放在证书库中。 您可以在应用中携带证书或公钥。

 // Encoded RSAPublicKey private static String PUB_KEY = "30818902818100C4A06B7B52F8D17DC1CCB47362" + "C64AB799AAE19E245A7559E9CEEC7D8AA4DF07CB0B21FDFD763C63A313A668FE9D764E" + "D913C51A676788DB62AF624F422C2F112C1316922AA5D37823CD9F43D1FC54513D14B2" + "9E36991F08A042C42EAAEEE5FE8E2CB10167174A359CEBF6FACC2C9CA933AD403137EE" + "2C3F4CBED9460129C72B0203010001"; public static void Main(string[] args) { ServicePointManager.ServerCertificateValidationCallback = PinPublicKey; WebRequest wr = WebRequest.Create("https://encrypted.google.com/"); wr.GetResponse(); } public static bool PinPublicKey(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { if (null == certificate) return false; String pk = certificate.GetPublicKeyString(); if (pk.Equals(PUB_KEY)) return true; // Bad dog return false; } 

对于未来遇到此问题的任何人,应该注意,在续订证书时,某些证书颁发机构将不再使用相同的公钥重新颁发证书。 我们特别向Globalsign提出了这个问题,他们给我们留下了非常困难的后勤问题,即在很短的时间内为所有客户更新客户端软件的新公钥固定细节,尽管他们发布的政策文件说他们提供了选项重用公钥。 如果这可能是您提前确认证书提供商政策的问题,请勿使用Globalsign!

客户端可以像下面一样使用ServerCertificateValidationCallback

  System.Net.ServicePointManager.ServerCertificateValidationCallback += delegate(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate, System.Security.Cryptography.X509Certificates.X509Chain chain, System.Net.Security.SslPolicyErrors sslPolicyErrors) { return true; };