我有一个客户端-服务器设置。
客户端创建代理以便与服务器通信。当通信协议为 HTTPS 时,代理通过以下行侦听 SSL 证书验证事件:
ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback(ValidateRemoteCertificate);
ValidateRemoteCertificate 方法处理证书异常。
在客户端中,用户可以选择 3 个安全级别之一:低、中和高。
在低级别,ValidateRemoteCertificate 方法会忽略任何错误并始终返回 true。
在中级别,ValidateRemoteCertificate 方法会触发一个事件,通知客户端存在问题。在此阶段,用户会看到一条消息,通知他证书有问题,并允许用户选择是继续并接受与服务器的连接还是拒绝。
在高级别中,ValidateRemoteCertificate 方法会拒绝任何错误的连接。
到目前为止,一切都很好。
场景如下:
- 客户端加载预定义的“中”安全级别,该级别已被用户接受,并且与服务器建立连接,而不会传播任何证书问题。
- 用户断开客户端与服务器的连接(通过特殊按钮)。
- 用户尝试重新连接客户端。在此阶段,客户端可以通过测试按钮测试连接。尽管已为连接测试创建了新代理,并且所有 ValidateRemoteCertificate 方法已从 ServerCertificateValidationCallback(特定代理类型)中清除,但测试方法仍返回成功。此外,不会针对有问题的证书触发任何事件,并且不会调用 ValidateRemoteCertificate 方法。
我试图实现的行为是,执行测试时,ServerCertificateValidationCallback 的行为就像是客户端启动后第一次调用它,并且 ValidateRemoteCertificate 将发挥作用。
我尝试寻找任何清除 ServicePointManager 中的任何委托/事件的方法,但我找不到任何方法。
这里有缓存可以清除吗?
我希望这个场景足够清晰。
我知道已经过去近 4 年了,但我也遇到了同样的问题,并且想分享我的解决方案,以防其他人发现这个问题。
我找不到任何内置方法来处理此问题,因此查看了 ServicePoint 和 ServicePointManager 的源代码,这就是我想到的:
public void EnsureNoServicePointCertificate(Uri uri)
{
// find the service point for the Uri
ServicePoint sp = ServicePointManager.FindServicePoint(uri);
// Check if there is a service point and there is a certificate
if (sp != null && sp.Certificate != null)
{
try
{
// ServicePointManager has a hashtable (private static Hashtable s_ServicePointTable) of all service points
Type servicePointType = sp.GetType();
// ServicePoint.LookupString is the key for the hashtable
PropertyInfo lookupStringProperty = servicePointType.GetProperty("LookupString", BindingFlags.Instance | BindingFlags.NonPublic);
string lookupString = (string)lookupStringProperty.GetValue(sp, null);
// Get the hashtable from ServicePointManager
Hashtable s_ServicePointTable = (Hashtable)typeof(ServicePointManager).InvokeMember("s_ServicePointTable",
BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.GetField, null, null, null);
// ServicePointManager locks the hashtable and calls
// s_ServicePointTable.Remove(servicePoint.LookupString);
lock (s_ServicePointTable)
{
s_ServicePointTable.Remove(lookupString);
}
// At this point, ServicePointManager calls
// servicePoint.ReleaseAllConnectionGroups();
MethodInfo release = servicePointType.GetMethod("ReleaseAllConnectionGroups", BindingFlags.Instance | BindingFlags.NonPublic);
release.Invoke(sp, null);
}
catch { }
}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)