zl程序教程

您现在的位置是:首页 >  后端

当前栏目

[C#]用HttpWebRequest加载证书建立SSL通道时发生异常的解决办法

c#SSL异常 加载 解决办法 建立 证书 发生
2023-09-14 08:58:21 时间

对于用HttpWebRequest加载证书请求远端https服务器时,发生的

“基础连接已经关闭: 无法与远程服务器建立信任关系。”/

“The underlying connection was closed. Could not establish a secure SSL/TLS connection”错误,我们可以用如下方式解决。

重现:

使用以下代码,你就可以得到这个错误“基础连接已经关闭: 无法与远程服务器建立信任关系”:

using System;

using System.Text;

using System.Net;

using System.IO;

using System.Security.Cryptography.X509Certificates;

 

using Microsoft.Web.Services2.Security;

using Microsoft.Web.Services2.Security.Tokens;

using Microsoft.Web.Services2.Security.X509;

 

static void Main(string[] args)

        {

            StringBuilder sb=new StringBuilder();

            string _strToRequest = "send";

 

            try

            {

                //POST请求开始

                byte[] bt=Encoding.Default.GetBytes("send");

                HttpWebRequest Req=(HttpWebRequest)System.Net.WebRequest.Create("https://202.108.CCC.XXX:Port//");

                Req.KeepAlive=true;

                //Req.Timeout=60000;

                Req.ContentType="text/xml";

                Req.ContentLength=_strToRequest.Length;

                Req.Method="POST";

                X509CertificateStore store = X509CertificateStore.CurrentUserStore( X509CertificateStore.MyStore );

                store.OpenRead();

    

                //读取证书的keyid

                Microsoft.Web.Services2.Security.X509.X509CertificateCollection certs =

                    store.FindCertificateByKeyIdentifier( Convert.FromBase64String( "CXv+xZ78zI3qWHGJ6Wh9BF6B23A=" ) );

                X509SecurityToken token = null;

                if (certs.Count 0)

                {

                    // 得到证书存储区的第1个人证书

                    token = new X509SecurityToken( ((Microsoft.Web.Services2.Security.X509.X509Certificate) certs[0]) );

                } 

                if(token != null)

                    Req.ClientCertificates.Add(token.Certificate);

                Req.KeepAlive=true;

 

                Stream ReqStream=Req.GetRequestStream();

                ReqStream.Write(bt,0,bt.Length);

                ReqStream.Close();

                //得到响应

                HttpWebResponse res=(HttpWebResponse)Req.GetResponse();

                StreamReader sr=newStreamReader(res.GetResponseStream(),Encoding.Default);

                sb.Append(sr.ReadToEnd());

                res.Close();

                sr.Close();

            }

            catch(Exception ex)

            {    

                sb.Remove(0,sb.Length);

                sb.Append(" ?xml version=\"1.0\" encoding=\"gb2312\"? \n");

                sb.Append(" slia ver=\"1.0.0\" \n");

                sb.Append(" result resid=\"501\" "+ex.Message+" /result \n");

                sb.Append(" /slia \n");

            }

 

            Console.WriteLine(sb.ToString());

 

            Console.Read();

        }

原因:

在“http://msdn.microsoft.com/library/chs/default.asp?url=/library/CHS/cpguide/html/cpconhostingremoteobjectsininternetinformationservicesiis.asp”提到:

证书标识特定的计算机,该计算机的名称位于证书的公共名称中。但是,很容易就会更改计算机的名称或使用客户端配置文件中的“localhost”,这会在客户端和服务器证书中的公共名称之间造成不匹配的情况。在 .NET Framework 1.0 版中,这一不匹配的情况将被忽略,并且将在服务器上引发调用。

从 .NET Framework 1.1 版开始,这一不匹配的情况会引发以下异常:“System.Net.WebException:基础连接已经关闭:无法与远程服务器建立信任关系”。如果您无法配置远程处理客户端以使用证书公共名称,则可以使用客户端应用程序配置文件中的以下设置重写这一不匹配的情况。

system.net

    settings

       servicePointManager

         checkCertificateName="true"

      /

    /settings

/system.net

若要以编程方式使客户端忽略证书名称不匹配,客户端必须创建一个特定类的实例,如果 certificateProblem值为 0x800c010f,该类将实现 ICertificatePolicy 接口并实现 CheckValidationResult 方法以返回true。然后,您必须将该对象注册到 System.Net.ServicePointManager 对象,方法是将该对象传递到ServicePointManager.CertificatePolicy 属性。”

解决之道:

但是用它列出的代码还是不对,我们改为CheckValidationResult无条件返回true即可。如下所示声明一个TrustAllCertificatePolicy类:

 

public class TrustAllCertificatePolicy : System.Net.ICertificatePolicy

        {

            public TrustAllCertificatePolicy()

            {}

 

            public bool CheckValidationResult(ServicePoint sp,

                System.Security.Cryptography.X509Certificates.X509Certificate cert,

                WebRequest req, int problem)

            {

                return true;

            }

        }

然后,在请求之前加上

System.Net.ServicePointManager.CertificatePolicy = new TrustAllCertificatePolicy();

即可。

这样,代码就可以顺利和https服务器建立SSL通道了。

编写者:郑昀@UltraPower


阿里云免费版SSL云盾证书申请流程 ssl证书可以快速实现域名由http升级为https,防止网站被拦截、被篡改、被劫持、被仿冒,阿里云提供免费版的SSL云盾证书,但是很多用户却找不到申请入口,下面就介绍下如何申请阿里云免费版SSL云盾证书。
关于 SSL 证书 在 HTTPS 协议大行其道的今天,其通信所需要的 SSL 证书也是不可或缺的一环,如果访问没有 SSL 证书的网站,就是下面这样的
郑昀 ☑移动数据业务 times;6年 ☑语义聚合 times;4年 ☑O2O times;5年的一个老兵。