c# - 带有证书的 WebRequest 在第一次调用时失败,并在所有后续调用中成功
问题描述
基础设施
我有一个从旧服务器迁移的旧 .NET Framework 应用程序。它在 Windows Server 2012 R2 上运行的 4.6.2。
表单应用程序调用也在同一应用程序池下的同一服务器中运行的 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;
}
}
我尝试过的事情
尝试将协议设置为 TLS 1.2:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
根据相同的建议,尝试将应用程序池标识更改为 Network Service、LocalSystem 和 LocalService,但均无效。
其他信息
应用程序池是推荐的身份“ApplicationPoolIdentity”,并且“加载用户配置文件”设置设置为 true,否则不会加载证书。
我想不出下一步该做什么,需要一些帮助来理解和修复这种行为
解决方案
现在通过添加这些键似乎可以工作:
X509KeyStorageFlags.UserKeySet |
X509KeyStorageFlags.MachineKeySet |
X509KeyStorageFlags.PersistKeySet |
X509KeyStorageFlags.Exportable
谢谢
推荐阅读
- java - 如何处理这种类型的异常?
- javascript - Socket IO 和动态房间
- swiftui - SwiftUI 中的 Google AdMob 集成
- javafx - 无法使用 Gluon Connect 使用 Twitter 搜索 API 响应填充 JavaFX 表格视图
- java - 包含不同对象的 2 个列表的公共部分
- javascript - Puppeteer - 获取父元素
- reactjs - 带有 TypeError 结果的 Netlify 部署:无法读取未定义的属性“替换”
- linux - 将输出发送到另一个命令
- javascript - 如果在内部单击并在外部释放鼠标,则模式关闭
- php - 本地主机/~用户名/不适用于 Mojave