你能强迫HttpClient只信任一个证书吗?
我知道你可以这样做:
WebRequestHandler handler = new WebRequestHandler();
X509Certificate2 certificate = GetMyX509Certificate();
handler.ClientCertificates.Add(certificate);
HttpClient client = new HttpClient(handler);
但这会迫使它只信任该单一证书,还是会信任证书和所有证书fx。 GlobalSign可以验证吗?
基本上我想确保它只能是我的客户正在与我交谈的服务器/证书。
答案 0 :(得分:15)
你能强迫HttpClient只信任一个证书吗? ... 基本上我想确保它只能是我的客户正在与我交谈的服务器/证书。
是。但什么类型的证书?服务器还是CA?两者的例子如下。
此外,在服务器的情况下,固定公钥而不是证书可能更好。这是因为像谷歌这样的组织每30天左右轮换一次服务器证书,以保证移动客户端的CRL小。但是,组织将重新验证相同的公钥。
以下是从Use a particular CA for a SSL connection固定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' Certificate and Public Key Pinning固定服务器证书的示例。它不要求将证书放在证书存储区中。您可以在应用中携带证书或公钥。
// 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;
}
答案 1 :(得分:2)
对于今后遇到此问题的任何人,应该注意,在续订证书时,某些证书颁发机构将不再使用相同的公钥重新颁发证书。我们特别向Globalsign提出了这个问题,他们给我们留下了非常困难的后勤问题,即在很短的时间内为所有客户更新客户端软件的新公钥固定细节,尽管他们发布的政策文件表明他们提供了选项重用公钥。如果这可能是您提前确认证书提供商政策的问题,请勿使用Globalsign!
答案 2 :(得分:-9)
客户可以使用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;
};