asp.net在IIS环境中访问第三方需数字证书接口时 报 “请求被中止: 未能创建 SSL/TLS 安全通道”

本文介绍了解决IIS环境中因SSL证书授权问题导致的请求失败的方法。通过导入证书并使用winhttpcertcfg工具授权给正确的账户,修改代码以从证书存储中加载证书。

最近做一个网站,需要访问第三方的接口(访问接口需要数字证数 *.pfx  文件),在VS环境下运行时完全正常,但放到IIS上就报"请求被中止: 未能创建 SSL/TLS 安全通道"、 “The request was aborted: Could not create SSL/TLS secure channel”。在网上找好久终于找到方法,在此与大家分享下,希望对遇到同样问题的 程序猿 有所帮助。


前题引如下以类库

using System.IO;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;


最初完整源码如下:

    /// <summary>
    /// xxx
    /// </summary>
    /// <param name="xmlStr">xxx</param>
    /// <returns></returns>

   private string xmlSubject(string xmlStr)

    {

        string retXml = "";
        ServicePointManager.Expect100Continue = true;
        ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;   //SSL3协议替换成TLS协议
        ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
        HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create("https://xxxxxxx");
        
        X509Certificate cerCaiShang = new X509Certificate(“D:\Work\xxx.pfx”, "123456", X509KeyStorageFlags.MachineKeySet);
        httpRequest.ClientCertificates.Add(cerCaiShang);
        httpRequest.Method = "POST";
        httpRequest.ContentType = "application/x-www-form-urlencoded";
       
        byte[] payload = System.Text.Encoding.UTF8.GetBytes(xmlStr);                                    
        httpRequest.ContentLength = payload.Length;                                                 

        using (Stream writer = httpRequest.GetRequestStream())                                          
        {
            writer.Write(payload, 0, payload.Length);                                                 
            HttpWebResponse response = (HttpWebResponse)httpRequest.GetResponse();               
            using (StreamReader srd = new StreamReader(response.GetResponseStream(), System.Text.Encoding.Default))
            {
                retXml = srd.ReadToEnd();              //读取文件流
                retXml = retXml.Replace("&lt;", "<");  //特殊字符处理
                retXml = retXml.Replace("&gt;", ">");  //特殊字符处理
            }
            response.Close();
        }
        return retXml;

   }


    /// <summary>
    /// 回调方法
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="certificate"></param>
    /// <param name="chain"></param>
    /// <param name="errors"></param>
    /// <returns></returns>
    public static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
    {
        //为了通过证书验证,总是返回true
        return true;
    }


以上源码在VS环境 及 WinForm 程序中运行完全正常,但在IIS上就报  "请求被中止: 未能创建 SSL/TLS 安全通道",   经查找资料才知是 IIS 受权问题

解决办法及步骤如下:

1.将客户端证书文件导入到  本地计算机账户  下的个人存储区。

2.下载winhttpcertcfg.exe 这个工具,下载地址:http://www.microsoft.com/en-us/download/details.aspx?id=19801

3.安装后 进入cmd 执行:

    a. cd C:\Program Files\Windows Resource Kits\Tools  

    b. winhttpcertcfg -g -c LOCAL_MACHINE\MY -s "test" -a "NetworkService"


第1点中 导入证书方法如下:

将客户端的证书+私钥(pfx 或p12 文件),导入到操作系统(windows)的相关证书区域,步骤:
    Windows xp/2003
        1. 单击 开始 ,单击 运行 ,键入 mmc ,然后单击 确定 。
        2. 在 文件 菜单上单击 添加/删除管理单元 。
        3. 在 添加/删除管理单元 对话框中,单击 添加 。
        4. 在 添加独立管理单元 对话框单击 证书 ,然后单击 添加 。
        5. 在在 证书管理单元中 对话框中单击 计算机帐户 ,然后单击 下一步
        6. 在 选择计算机 对话框中,单击 完成 。
        7. 在 添加独立管理单元 对话框单击 关闭 ,然后单击 确定 。
        8. 展开 证书 (本地计算机) ,展开 个人 ,然后单击 证书 。
        9. 右键 -》 所有任务-》导入 选择你的证书导入
    Windows 7
        1. 单击 开始 ,单击 运行 ,键入 mmc ,然后单击 确定 。
        2. 在 文件 菜单上单击 添加/删除管理单元 。
        3. 在 可用的管理单元 列表中选择 证书 ,点击 添加 。
        4. 在 证书管理 对话框中选择 计算机账户 ,然后单击 下一步
        5. 在 选择计算机 对话框中,单击 完成 。
        6. 在 添加或删除管理单元 对话框单击 确定 。
        7. 展开 证书 (本地计算机) ,展开 个人 ,然后单击 证书 。
        8. 右键 -》 所有任务-》导入 选择你的证书导入


第3点中的参数含义:
-g 是grant授权的意思,将该证书的使用权限授予某个用户
-c 是certstore证书存储区,指定 本地计算机/当前用户下的证书存储区位置,我们这里是MY,个人存储区
-s 是subjectstr 用于模糊匹配证书的一个字符串,我们这里用证书文件名 test
-a 是account要授权的用户帐号

这里要注意的是授权账户,IIS6下面一般用的是NetworkService,如果你用的IIS7,必须要保证你网站所用的 应用程序池的 "标识"和要授权的账户一致。其它版本不用设置


执行成功之后,会列出模糊匹配出的证书列表和已经授权的账户.
然后程序代码做如下更改:

   private string xmlSubject(string xmlStr)

    {
        string retXml = "";
        ServicePointManager.Expect100Continue = true;
        ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
        ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
        HttpWebRequest httpRequest = (HttpWebRequest)HttpWebRequest.Create("https://xxxxxxx");

        X509Store certStore = new X509Store(StoreName.My, StoreLocation.LocalMachine);
        certStore.Open(OpenFlags.ReadOnly);
        X509Certificate2Collection certCollection = certStore.Certificates.Find(X509FindType.FindBySubjectName, "xxx", false);

        httpRequest.ClientCertificates.Add(certCollection[0]);
        httpRequest.Method = "POST";
        httpRequest.ContentType = "application/x-www-form-urlencoded";
      
        byte[] payload = System.Text.Encoding.UTF8.GetBytes(xmlStr);                              
        httpRequest.ContentLength = payload.Length;                                                
        using (Stream writer = httpRequest.GetRequestStream())                                           
        {
            writer.Write(payload, 0, payload.Length);                                                  
            HttpWebResponse response = (HttpWebResponse)httpRequest.GetResponse();                
            using (StreamReader srd = new StreamReader(response.GetResponseStream(), System.Text.Encoding.Default))
            {
                retXml = srd.ReadToEnd();              //读取文件流
                retXml = retXml.Replace("&lt;", "<");  //特殊字符处理
                retXml = retXml.Replace("&gt;", ">");  //特殊字符处理
            }
            response.Close();
        }
        return retXml;

    }


更改后在VS 及 IIS中运行 OK ,问题圆满解决。

### 原因分析 在C#中发起请求出现“请求中止: 未能创建 SSL/TLS 安全通道”错误通常与SSL/TLS协议版本不兼容、证书问题或服务器端配置更改有关。以下是具体原因: 1. **SSL/TLS协议版本不兼容**:如果客户端使用的SSL/TLS协议版本与服务器端不兼容,会导致无法建立安全连接。例如,某些旧系统默认使用较老的协议版本(如TLS 1.0),而服务器可能已升级到仅支持TLS 1.2或更高版本[^4]。 2. **证书问题**:证书过期、未正确安装或不受信任的证书颁发机构(CA)可能导致连接失败。例如,微信支付的根证书更换后,如果未及更新相关证书,可能会导致此类错误[^2]。 3. **服务器端配置更改**:第三方服务提供方可能对服务器的安全配置进行了调整,例如禁用了某些不再推荐使用的加密套件或协议版本,导致客户端无法正常连接[^1]。 4. **操作系统和.NET Framework版本限制**:不同版本的Windows和.NET Framework支持的SSL/TLS协议版本不同。例如,Windows Server 2003默认不支持TLS 1.2,除非手动启用[^3]。 ### 解决方案 针对上述原因,可以采取以下措施来解决请求中止: 未能创建 SSL/TLS 安全通道”错误: 1. **强制使用TLS 1.2或更高版本** 在代码中显式设置`ServicePointManager.SecurityProtocol`以确保使用最新的TLS协议版本。建议使用TLS 1.2或更高版本,因为这些版本提供了更强的安全性和兼容性。 ```csharp System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; ``` 如果要兼容旧系统,可以同启用多个协议版本: ```csharp System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12; ``` 这种方式可以确保客户端尝试使用所有可用的协议版本进行连接,从而提高兼容性[^4]。 2. **更新和安装必要的证书** 确保所有相关的CA证书和API证书都已正确安装,并且是最新的版本。特别是对于微信支付等服务,务必按照官方文档的要求安装最新的根证书和中间证书[^2]。 3. **检查服务器端配置** 如果可能,联系第三方服务提供方确认其服务器的安全配置,包括支持的SSL/TLS协议版本和加密套件。确保客户端配置与服务器端兼容。 4. **升级操作系统和.NET Framework** 对于老旧的操作系统(如Windows Server 2003),建议升级到更新的版本(如Windows Server 2016或更高),以获得更好的安全性和协议支持。同,确保.NET Framework版本为4.6或更高,以便默认支持TLS 1.2[^3]。 5. **调试和日志记录** 在代码中添加详细的日志记录,捕获请求过程中的异常信息,帮助定位问题。可以使用`try-catch`块捕获`WebException`并检查响应流中的详细错误信息。 ```csharp try { // 发起请求的代码 } catch (WebException ex) { using (var response = (HttpWebResponse)ex.Response) { Console.WriteLine($"Status Code: {response?.StatusCode}"); Console.WriteLine($"Status Description: {response?.StatusDescription}"); } } ``` 通过以上方法,可以有效解决C#中发起HTTPS请求出现的“请求中止: 未能创建 SSL/TLS 安全通道”错误。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值