也许你们中的一位可以帮助我回答有关在 .NET 框架中验证证书的问题。不幸的是,我在网上搜索时只找到了我的问题的肤浅答案,但没有确切的解释。
同时我知道我可以使用以下代码在我的软件中检查证书是否有效。
ServicePointManager.ServerCertificateValidationCallback += ValidateRemoteCertificate;
private bool ValidateRemoteCertificate(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors policyErrors)
{
return policyErrors == SslPolicyErrors.None;
}
但我现在想知道微软到底在这里检查什么?框架执行了哪些检查才能得到结果 SslPolicyErrors.None?
例如,根证书是否也在此处进行验证以及它来自哪里?如果是这样,怎么办?
您认为是否仍然有必要(或有用)在这些检查中添加我自己的检查,而 .NET Framework 尚未进行这些检查?
这部分只是重复c#验证X509Certificate2:我这样做对吗?,那里的简短答案是您免费获得的检查(没有自定义处理程序,或者在您的处理程序之前已经完成) ):
SslPolicyErrors.RemoteCertificateChainErrors
)
SslPolicyErrors.RemoteCertificateNameMismatch
)例如,根证书是否也在此处进行验证以及它来自哪里?
此处的证书验证使用与 Internet Explorer、Chrome、Edge、Outlook 等相同的根信任列表,该列表在 Windows 中集中管理。 (Firefox 使用不同的根信任列表,该列表仅由 Firefox 管理。)
您认为...
StackOverflow 上的意见问题与主题无关。
仍然有必要(或有用)在这些检查中添加我自己的检查,而 .NET Framework 尚未进行这些检查?
这要看情况。
如果您正在联系自己的服务器之一,并且您知道有关证书链的一些信息,则可以添加额外的检查。例如,您可能知道您的服务器使用 Let's Encrypt,并且您在应用程序中嵌入了来自 https://letsencrypt.org/certificates/ 的“Let's Encrypt Authority X3”证书,然后您可以固定中间...只需确保在他们转向新的中间体时做出反应即可。
private bool ValidateRemoteCertificate(
object sender,
X509Certificate cert,
X509Chain chain,
SslPolicyErrors policyErrors)
{
if (policyErrors != SslPolicyErrors.None)
{
return false;
}
if (chain.ChainElements.Count != 3)
{
return false;
}
byte[] foundCert = chain.ChainElements[1].Certificate.RawData;
return s_letsEncryptX3Direct.SequenceEqual(foundCert) ||
s_letsEncryptX3Cross.SequenceEqual(foundCert);
}
如果您不打算执行额外的检查(或进行自定义日志记录等),那么最好甚至不要注册回调,因为当没有注册回调时,内存和 CPU 的实现会更好一些。
只需检查链条状态。已经有描述性消息:
[Test]
public async Task CheckWhatError()
{
var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = ValidateRemoteCertificate;
var client = new HttpClient(handler);
try
{
using (var msg = new HttpRequestMessage(HttpMethod.Get, "https://expired.badssl.com/"))
{
using (var response = await client.SendAsync(msg))
{
// do stuff with the response
}
}
}
catch (Exception ex)
{
throw;
}
}
private bool ValidateRemoteCertificate(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors policyErrors)
{
if(policyErrors == SslPolicyErrors.RemoteCertificateChainErrors)
{
foreach(var cs in chain.ChainStatus)
{
Console.WriteLine(cs.StatusInformation);//validation errors here
}
}
return policyErrors == SslPolicyErrors.None;
}
我在 c# 验证 X509Certificate2:我这样做对吗? 中发布了此内容,但我也会将其发布在这里以提高可见性。对于 .NET 5 及更高版本,请按照 https://github.com/dotnet/runtime/issues/39835:
中发布的示例进行操作RemoteCertificateValidationCallback callback = (object sender, X509Certificate? certificate, X509Chain? chain, SslPolicyErrors sslPolicyErrors) =>
{
if (sslPolicyErrors == SslPolicyErrors.None)
{
return true;
}
else if (sslPolicyErrors != SslPolicyErrors.RemoteCertificateChainErrors || chain is null || certificate is null)
{
// Name mismatch or no cert
return false;
}
// name matches and there was a certificate
// Only works with .NET 5 and higher, taken from
// https://github.com/dotnet/runtime/issues/39835
chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust;
chain.ChainPolicy.CustomTrustStore.Add(/* Load your root certificate here */);
chain.ChainPolicy.ExtraStore.Add(X509Certificate2.CreateFromPemFile(/* Load any intermediate certificates here */);
return chain.Build(new X509Certificate2(certificate));
};