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

简介:

编写者:郑昀@UltraPower

关键字:HttpWebRequest,

SSL,X509Certificate

dotNet  Framwork 1.1

编写时间:2005-3-29

WSE 2.0 SP3

 

目的:

对于用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

目录
相关文章
|
7月前
|
安全 网络安全 数据安全/隐私保护
ssl证书认证失败的原因和解决办法
ssl证书认证失败的原因和解决办法
|
4月前
|
安全 测试技术 数据库连接
如何避免 C# 中的异常
【8月更文挑战第27天】
58 2
|
4月前
|
安全 C# 开发者
【C# 多线程编程陷阱揭秘】:小心!那些让你的程序瞬间崩溃的多线程数据同步异常问题,看完这篇你就能轻松应对!
【8月更文挑战第18天】多线程编程对现代软件开发至关重要,特别是在追求高性能和响应性方面。然而,它也带来了数据同步异常等挑战。本文通过一个简单的计数器示例展示了当多个线程无序地访问共享资源时可能出现的问题,并介绍了如何使用 `lock` 语句来确保线程安全。此外,还提到了其他同步工具如 `Monitor` 和 `Semaphore`,帮助开发者实现更高效的数据同步策略,以达到既保证数据一致性又维持良好性能的目标。
58 0
|
6月前
|
开发框架 .NET 程序员
掌握C#语言的精髓:基础知识与实用技能详解(数据类型与变量+ 条件与循环+函数与模块+LINQ+异常+OOP)
掌握C#语言的精髓:基础知识与实用技能详解(数据类型与变量+ 条件与循环+函数与模块+LINQ+异常+OOP)
34 0
|
6月前
|
网络安全
阿里云申请Symantec 免费版 SSL证书提示 缺少必要的 审核材料 的解决办法
阿里云申请Symantec 免费版 SSL证书提示 缺少必要的 审核材料 的解决办法
|
7月前
|
网络安全 C#
C# HttpWebRequest 获取 HTTPS 网页内容
C# HttpWebRequest 获取 HTTPS 网页内容
781 0
|
7月前
|
开发框架 安全 .NET
C# .NET面试系列三:集合、异常、泛型、LINQ、委托、EF!
<h2>集合、异常、泛型、LINQ、委托、EF! #### 1. IList 接口与 List 的区别是什么? IList 接口和 List 类是C#中集合的两个相关但不同的概念。下面是它们的主要区别: <b>IList 接口</b> IList 接口是C#中定义的一个泛型接口,位于 System.Collections 命名空间。它派生自 ICollection 接口,定义了一个可以通过索引访问的有序集合。 ```c# IList 接口包含一系列索引化的属性和方法,允许按索引访问、插入、移除元素等。 由于是接口,它只定义了成员的契约,而不提供具体的实现。类似于 IEnumera
367 2
|
7月前
|
安全 编译器 C#
C#中的可空引用类型:减少空引用异常的利器
【1月更文挑战第9天】C# 8.0中引入的可空引用类型特性,它通过在编译时提供更精确的静态分析,帮助开发者减少运行时的空引用异常。文章详细阐述了可空引用类型的工作原理、如何配置项目以使用此特性,以及在实际编码中如何利用可空引用类型提升代码的健壮性和可读性。