使用ServerCertificateValidationCallback的最佳实践

gal*_*ets 29 .net c# ssl web-services webclient

我正在开发一个在两个后端服务器之间使用一些HTTP通信的项目.服务器使用X509证书进行身份验证.不用说,当服务器A(客户端)建立与服务器B(服务器)的连接时,存在SSL/TLS验证错误,因为使用的证书不是来自受信任的第三方权限.

通常,处理它的方法是使用ServicePointManager.ServerCertificateValidationCallback,例如:

ServicePointManager.ServerCertificateValidationCallback += 
        (sender, cert, chain, error) =>
{
    return cert.GetCertHashString() == "xxxxxxxxxxxxxxxx";
};
Run Code Online (Sandbox Code Playgroud)

这种方法有效,除非它不理想.它本质上做的是覆盖应用程序完成的每个http请求的验证过程.因此,如果另一个类将尝试运行HTTP请求,它将失败.此外,如果另一个类ServicePointManager.ServerCertificateValidationCallback为了自己的目的而覆盖,那么我的通信开始突然失败.

想到的唯一解决方案是创建一个单独的AppDomain来执行客户端HTTP请求.这可行,但实际上 - 只有这样才能执行HTTP请求是愚蠢的.开销将是惊人的.

考虑到这一点,是否有人研究过.NET中是否有更好的实践,这将允许访问Web服务,同时处理客户端SSL/TLS验证而不影响其他Web客户端?

gal*_*ets 33

在.NET 4.5+中使用的可接受(安全)方法是使用.在特定的请求实例上分配该回调将仅针对请求更改验证逻辑,而不会影响其他请求.HttpWebRequest.ServerCertificateValidationCallback

var request = (HttpWebRequest)WebRequest.Create("https://...");
request.ServerCertificateValidationCallback += 
        (sender, cert, chain, error) =>
{
    return cert.GetCertHashString() == "xxxxxxxxxxxxxxxx";
};
Run Code Online (Sandbox Code Playgroud)

  • 另外,对于那些使用`HttpClient`而不是`HttpWebRequest`的人来说,`ServerCertificateValidationCallback`属性在你传递给`HttpClient`构造函数的`WebRequestHandler`对象上结束.(这是您已经用于设置客户端证书的对象,因此这是一个简单的添加.) (8认同)
  • 为了完整起见,ServerNetTertificateValidationCallback属性不适用于.Net Framework中的[FtpWebRequest](https://msdn.microsoft.com/en-us/library/system.net.ftpwebrequest(v = vs.110).aspx) 4.5 (3认同)
  • 我可以在生成的wcf服务参考上使用这种方法吗?我坐在这里是System.ServiceModel.ClientBase的生成的子类,但是除了通过执行问题中介绍的“全局”方式之外,我找不到在哪里插入此行为。 (2认同)

cka*_*ras 13

不使用HttpWebRequest的代码的替代方案,以及无法在证书存储中安装可信证书的环境:检查回调的错误参数,该参数将包含在回调之前检测到的任何错误.这样,您可以忽略特定哈希字符串的错误,但仍接受通过验证的其他证书.

ServicePointManager.ServerCertificateValidationCallback += 
    (sender, cert, chain, error) =>
{
    if (cert.GetCertHashString() == "xxxxxxxxxxxxxxxx")
    {
        return true;
    }
    else
    {
       return error == SslPolicyErrors.None;
    }
};
Run Code Online (Sandbox Code Playgroud)

参考:https: //msdn.microsoft.com/en-us/library/system.net.security.remotecertificatevalidationcallback(v=vs.110).aspx

请注意,这仍将影响同一appdomain中的其他Web客户端实例(它们都将接受指定的哈希字符串),但至少它不会阻止其他证书.

  • 我更喜欢您的答案,因为它允许您维护白名单并允许其他人正常实施。 (2认同)

500*_*ror 6

此方案的直接方法应该是在客户端计算机上的受信任根存储中安装两个自生成的证书.执行此操作时,您将收到安全警告,因为无法使用Thawte或类似程序对证书进行身份验证,但在此之后应进行常规安全通信.IIRC,您需要在受信任的根目录中安装完整(公钥和私钥)版本才能使用.


Mat*_*ach 6

我知道参加聚会有点晚了,但另一种选择是使用继承的类IDisposable,该类可以放在using(){}代码周围的块中:

public class ServicePointManagerX509Helper : IDisposable
{
    private readonly SecurityProtocolType _originalProtocol;

    public ServicePointManagerX509Helper()
    {
        _originalProtocol = ServicePointManager.SecurityProtocol;
        ServicePointManager.ServerCertificateValidationCallback += TrustingCallBack;
    }

    public void Dispose()
    {
        ServicePointManager.SecurityProtocol = _originalProtocol;
        ServicePointManager.ServerCertificateValidationCallback -= TrustingCallBack;
    }

    private bool TrustingCallBack(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
    {
        // The logic for acceptance of your certificates here
        return true;
    }
}
Run Code Online (Sandbox Code Playgroud)

以这种方式使用:

using (new ServicePointManagerX509Helper())
{
    // Your code here
}
Run Code Online (Sandbox Code Playgroud)

  • 这不是一个好方法,因为它仍然会全局关闭所有请求的所有验证,直到代码转义 using 块。 (2认同)