我有一个简单的web服务调用,由。net (c#) 2.0 Windows应用程序生成,通过Visual Studio生成的web服务代理,用于同样用c#(2.0)编写的web服务。这种方法已经有效了好几年,并且在十几个正在运行的地方继续有效。

在新地点的新安装遇到了问题。当试图调用web服务时,它失败了,消息说:

无法为SSL/TLS安全建立信任关系 通道

web服务的URL使用SSL (https://)——但这已经在许多其他位置工作了很长时间(并继续这样做)。

我该往哪里看?这可能是Windows和。net之间的安全问题,是此安装独有的吗?如果是,我在哪里建立信任关系?我迷路了!


当前回答

对于那些通过VS客户端遇到这个问题的人,一旦成功添加了一个服务引用,并试图执行第一个调用,就会得到这个异常: "底层连接已关闭:无法为SSL/TLS安全通道建立信任关系" 如果你正在使用(就像我的例子)一个带有IP地址的端点URL并得到了这个异常,那么你可能需要重新添加服务引用,执行以下步骤:

在Internet Explorer上打开端点URL。 点击证书错误(地址栏中的红色图标) 单击查看证书。 获取颁发给:“name”并替换IP地址或任何我们正在使用的名称,并得到这个“name”的错误。

再试一次:)。 谢谢

其他回答

如果没有工作坏证书,当ServerCertificateValidationCallback返回true; 我的ServerCertificateValidationCallback代码:

ServicePointManager.ServerCertificateValidationCallback += delegate
{
    LogWriter.LogInfo("Проверка сертификата отключена, на уровне ServerCertificateValidationCallback");
    return true;
};

我的代码被阻止执行ServerCertificateValidationCallback:

     if (!(ServicePointManager.CertificatePolicy is CertificateValidation))
    {
        CertificateValidation certValidate = new CertificateValidation();
        certValidate.ValidatingError += new CertificateValidation.ValidateCertificateEventHandler(this.OnValidateCertificateError);
        ServicePointManager.CertificatePolicy = certValidate;
    }

OnValidateCertificateError功能:

private void OnValidateCertificateError(object sender, CertificateValidationEventArgs e)
{
    string msg = string.Format(Strings.OnValidateCertificateError, e.Request.RequestUri, e.Certificate.GetName(), e.Problem, new Win32Exception(e.Problem).Message);
    LogWriter.LogError(msg);
    //Message.ShowError(msg);
}

我禁用了CertificateValidation代码和ServerCertificateValidationCallback运行得很好

我个人最喜欢以下解决方案:

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

... 然后在请求获取错误之前,执行以下操作

System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };

这是在咨询卢克的解决方案后发现的

Luke写了一篇关于这方面的好文章。 非常直截了当。试试吧

卢克的解决方案

原因(引用自他的文章(含诅咒)) “. . 上面的代码的问题是,如果您的证书无效,它将无法工作。为什么我要发布到一个网页与无效的SSL证书?因为我很便宜,我不想付钱给Verisign或其他** *的人对我的测试箱进行认证,所以我自己签名了。当我发送请求时,我得到了一个可爱的例外:

System.Net.WebException 底层连接被关闭。无法与远程服务器建立信任关系。

我不知道你怎么想,但对我来说,这个异常看起来像是由我的代码中一个愚蠢的错误引起的,导致POST失败。所以我一直在寻找,调整,做各种奇怪的事情。只有在我谷歌了***n的东西,我发现遇到无效的SSL证书后的默认行为是抛出这个异常。 . .”

下面的代码片段将修复您正在调用的服务器上的SSL证书有问题的情况。例如,证书可能是自签名的,或者证书和服务器之间的主机名可能不匹配。

如果您正在调用您直接控制之外的服务器,这是危险的,因为您不能再确定您正在与您认为连接到的服务器通信。但是,如果您处理的是内部服务器,而获得“正确的”证书是不现实的,请使用以下命令告诉web服务忽略证书问题并勇敢地继续工作。

前两个使用lambda表达式,第三个使用常规代码。第一个接受任何证书。后两者至少检查证书中的主机名是否是您所期望的主机名。 ... 希望对你有帮助

//Trust all certificates
System.Net.ServicePointManager.ServerCertificateValidationCallback =
    ((sender, certificate, chain, sslPolicyErrors) => true);

// trust sender
System.Net.ServicePointManager.ServerCertificateValidationCallback
                = ((sender, cert, chain, errors) => cert.Subject.Contains("YourServerName"));

// validate cert by calling a function
ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback(ValidateRemoteCertificate);

// callback used to validate the certificate in an SSL conversation
private static bool ValidateRemoteCertificate(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors policyErrors)
{
    bool result = cert.Subject.Contains("YourServerName");
    return result;
}

我已经用了一段时间了如果有用的话。

调用方必须显式地请求需要不受信任的认证,并在完成时将回调放回默认状态。

    /// <summary>
    /// Helper method for returning the content of an external webpage
    /// </summary>
    /// <param name="url">URL to get</param>
    /// <param name="allowUntrustedCertificates">Flags whether to trust untrusted or self-signed certificates</param>
    /// <returns>HTML of the webpage</returns>
    public static string HttpGet(string url, bool allowUntrustedCertificates = false) {
        var oldCallback = ServicePointManager.ServerCertificateValidationCallback;
        string webPage = "";
        try {
            WebRequest req = WebRequest.Create(url);

            if (allowUntrustedCertificates) {
                // so we can query self-signed certificates
                ServicePointManager.ServerCertificateValidationCallback = 
                    ((sender, certification, chain, sslPolicyErrors) => true);
            }

            WebResponse resp = req.GetResponse();
        
            using (StreamReader sr = new StreamReader(resp.GetResponseStream())) {
                webPage = sr.ReadToEnd().Trim();
                sr.Close();
            }
            return webPage;
        }
        catch {
            // if the remote site fails to response (or we have no connection)
            return null;
        }
        finally {
            ServicePointManager.ServerCertificateValidationCallback = oldCallback;
        }
    }