带有证书的 WebRequest 在第一次调用时失败,并在所有后续调用中成功
Posted
技术标签:
【中文标题】带有证书的 WebRequest 在第一次调用时失败,并在所有后续调用中成功【英文标题】:WebRequest with certificate fails on first call and succeeds all subsequent calls 【发布时间】:2020-08-21 06:33:57 【问题描述】:基础设施
我有一个从旧服务器迁移的旧 .NET Framework 应用程序。 它在 4.6.2 中运行在 Windows Server 2012 R2 上。
表单应用程序调用也在同一应用程序池下的同一服务器中运行的 WCF 服务,而 WCF 服务对外部服务进行 WebRequest 调用。
外部调用需要 SSL/TLS 握手证书。
在旧服务器中,证书附加到请求中,但在新服务器中,这不起作用,我们必须将它们添加到信任库中。这可能是以下问题的重要线索。
问题
WCF 服务调用外部服务,第一次调用(在部署或重新启动应用程序后)总是错误The request was aborted: Could not create SSL/TLS secure channel.
但是,所有后续调用都成功运行。 就好像证书在第一次调用时没有正确加载到用户配置文件中一样,但之后却是。
这会导致在部署新版本后出现问题,所有首次调用都失败,从而影响实时流量。 我们在负载均衡器下的 6 个机器上具有相同的配置,并且所有 6 个机器上的行为都相同。
我想解决这个问题,以便在第一次通话时通话成功。
代码
public static Stream SendRequest(string url, string requestXml, string clientKeyBase64, string clientKeyPassword, int requestTimeout)
Stream os = null;
HttpWebRequest req = null;
WebResponse resp = null;
byte[] bytes;
try
req = (HttpWebRequest)WebRequest.Create(url);
req.Timeout = requestTimeout;
req.ContentType = "application/xml; charset=utf-8";
req.Method = "POST";
bytes = Encoding.ASCII.GetBytes(requestXml);
req.ContentLength = bytes.Length;
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
if (!string.IsNullOrWhiteSpace(clientKeyBase64))
var cert = new X509Certificate2(Convert.FromBase64String(clientKeyBase64), clientKeyPassword);
req.ClientCertificates.Add(cert);
using (os = req.GetRequestStream())
os.Write(bytes, 0, bytes.Length);
using (resp = req.GetResponse())
using (var stream = resp.GetResponseStream())
MemoryStream memStream;
memStream = new MemoryStream();
stream.CopyTo(memStream);
memStream.Seek(0, SeekOrigin.Begin); // Required to reset stream pointer at the beginning
return memStream;
catch (Exception ex)
throw ex;
我尝试过的事情
这篇标题为“WCF Client: First call fails, second call succeeds” 的文章与证书相关,非常有前途。但是,使用 ServicePointManager.Expect100Continue = true;
绕过 HTTP 状态 100 的建议不起作用。
尝试将协议设置为 TLS 1.2:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
尝试按照this suggestion设置X509KeyStorageFlags.MachineKeySet
根据相同的建议,尝试将应用程序池标识更改为 Network Service、LocalSystem 和 LocalService,但均无效。
其他信息
应用程序池是推荐的身份“ApplicationPoolIdentity”,并且“加载用户配置文件”设置设置为 true,否则不会加载证书。
我想不出下一步该做什么,需要一些帮助来理解和解决这种行为
【问题讨论】:
使用 Wireshark 等工具进一步了解握手失败的情况,从而更好地了解下一步该做什么。 由于部署新版本不会更新应用程序池,您是否尝试过部署后回收应用程序池或使用应用程序池初始化预热?听起来 schannel 在第一次通话时没有醒来。docs.microsoft.com/en-us/iis/get-started/whats-new-in-iis-8/… 感谢您的回答,已修复 【参考方案1】:现在通过添加这些键似乎可以工作:
X509KeyStorageFlags.UserKeySet |
X509KeyStorageFlags.MachineKeySet |
X509KeyStorageFlags.PersistKeySet |
X509KeyStorageFlags.Exportable
谢谢
【讨论】:
以上是关于带有证书的 WebRequest 在第一次调用时失败,并在所有后续调用中成功的主要内容,如果未能解决你的问题,请参考以下文章