最近做一个网站,需要访问第三方的接口(访问接口需要数字证数 *.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;
最初完整源码如下:
///
/// xxx
///
/// xxx
///
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("<", "<"); //特殊字符处理
retXml = retXml.Replace(">", ">"); //特殊字符处理
}
response.Close();
}
return retXml;
}
///
/// 回调方法
///
///
///
///
///
///
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)
{}
更改后在VS 及 IIS中运行 OK ,问题圆满解决。