【发布时间】:2015-04-25 00:23:02
【问题描述】:
我正在努力从我的 .NET 应用程序连接到仅通过 HTTPS/SSL 工作的 REST Web 服务。
我收到了证书和私钥作为两个单独的文件使用 - 一个包含证书的 certificate.pem 文件和包含私钥的 webservice.key 文件。这些都是文本文件,其中包含 BASE64 编码的二进制数据。
供应商还给我发了一份 PDF,展示了如何使用 CURL 和这两个文件调用该 Web 服务,效果很好:
curl.exe -k -v "https://(URL)" --cert certificate.pem --key webservice.key
我需要使用-k 选项,因为证书层次结构中的某处似乎有一个自签名证书。没有这个选项,调用会失败。
为了从 .NET 应用程序(目前是控制台应用程序)调用此 Web 服务,我使用 OpenSSL(在 Windows 上)使用以下命令将这两个文件组合成一个 *.pfx 文件:
openssl pkcs12 -export -out webservice.pfx -in certificate.pem -inkey webservice.key
这似乎也有效 - 没有报告错误,文件已创建并且大小约为 3K,并且是一个完全二进制文件。
现在,我尝试从我的 .NET 代码中调用该 Web 服务,如下所示:
try
{
// use the SSL protocol (instead of TLS)
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
// ignore any certificate complaints
ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => { return true; };
// create HTTP web request with proper content type
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
request.ContentType = "application/xml;charset=UTF8";
// grab the PFX as a X.509 certificate from disk
string certFileName = Path.Combine(certPath, "webservice.pfx");
// load the X.509 certificate and add to the web request
X509Certificate cert = new X509Certificate(certFileName, "(top-secret password)");
request.ClientCertificates.Add(cert);
request.PreAuthenticate = true;
// call the web service and get response
WebResponse response = request.GetResponse();
Stream responseStream = response.GetResponseStream();
}
catch (Exception exc)
{
// log and print out error
}
但是,我可以尝试任何我喜欢的东西(在ServicePointManager 和HttpWebRequest 上摆弄各种设置,但我不断收到这些错误:
WebException:底层连接已关闭:发送时发生意外错误。
IOException: Unable to read data from the transport connection: 一个现有的连接被远程主机强行关闭。
SocketException:一个现有的连接被远程主机强行关闭
并且没有响应 - 即使使用 CURL 与服务通信工作正常.....
我错过了什么?我对所有这些证书、私钥、服务点管理器选项等感到有点困惑和迷惑——只是 waaaaay 太多的旋钮和开关无法打开、设置或关闭——正确是什么设置在这里??
更新:
如果我使用
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;
那么错误就是:
WebException:请求被中止:无法创建 SSL/TLS 安全通道。
S O L U T I O N:
最后,通过查看curl 的输出以及来自@Alexandru 和@JurajMajer 的大量帮助,我得以使用此代码:
try
{
// use the TLS protocol
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;
// create HTTP web request with proper content type
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
request.ContentType = "application/xml;charset=UTF8";
// grab the PFX as a X.509 certificate from disk
string certFileName = Path.Combine(certPath, "webservice.pfx");
// load the X.509 certificate and add to the web request
X509Certificate2 cert = new X509Certificate2(certFileName, "(top-secret password)");
request.ClientCertificates.Add(cert);
request.PreAuthenticate = true;
// call the web service and get response
WebResponse response = request.GetResponse();
Stream responseStream = response.GetResponseStream();
string xmlContents = new StreamReader(responseStream).ReadToEnd();
}
catch (Exception exc)
{
// log and print out error
}
【问题讨论】:
-
您的异常中是否有任何有意义的内部异常?
-
@Alexandru:这是我得到的唯一一个异常 (
WebException) 及其两个内部异常 -
如果您不忽略证书投诉,是否会引发一些有意义的错误?
-
顺便说一句,您可能想考虑让 Fiddler 调试这个问题 (telerik.com/download/fiddler)。工具 -> Fiddler 选项 -> HTTPS -> 勾选 Capture HTTPS CONNECTs 和 Decrypt HTTPS 流量。它安装了一个根 CA,开始签署所有证书,因此它在本地执行中间人攻击以解密通信。
-
@Alexandru:不,不忽略证书问题不会改变任何事情。而且我已经广泛尝试了 Fiddler,但我从来没有能够让它与这个服务一起工作(即使是关于这个的关于这个的问题也没有导致任何解决方案)
标签: c# web-services rest ssl certificate