English 中文(简体)
无法建立SSL/TLS安全通道的信任关系--SOAP
原标题:
  • 时间:2009-03-31 22:07:28
  •  标签:

I have a simple web service call, generated by a .NET (C#) 2.0 Windows app, via the web service proxy generated by Visual Studio, for a web service also written in C# (2.0). This has worked for several years, and continues to do so at the dozen or so places where it is running.

A new installation at a new site is running into a problem. When attempting to invoke the web service, it fails with the message saying:

Could not establish a trust relationship for the SSL/TLS secure channel

网络服务的URL使用SSL(https://)-- 但这已经在许多其他位置工作了很长时间(并且仍然如此)。

我该看哪里?这可能是一个在此安装中独特于Windows和.NET有关的安全问题吗?如果是,我该在哪里建立信任关系?我迷失了!

最佳回答

想法(基于过去的痛苦):

  • do you have DNS and line-of-sight to the server?
  • are you using the correct name from the certificate?
  • is the certificate still valid?
  • is a badly configured load balancer messing things up?
  • does the new server machine have the clock set correctly (i.e. so that the UTC time is correct [ignore local time, it is largely irrelevent]) - this certainly matters for WCF, so may impact regular SOAP?
  • is there a certificate trust chain issue? if you browse from the server to the soap service, can you get SSL?
  • related to the above - has the certificate been installed to the correct location? (you may need a copy in Trusted Root Certification Authorities)
  • is the server s machine-level proxy set correctly? (which different to the user s proxy); see proxycfg for XP / 2003 (not sure about Vista etc)
问题回答

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

This is dangerous if you are calling a server outside of your direct control, since you can no longer be as sure that you are talking to the server you think you re connected to. However, if you are dealing with internal servers and getting a "correct" certificate is not practical, use the following to tell the web service to ignore the certificate problems and bravely soldier on.

The first two use lambda expressions, the third uses regular code. The first accepts any certificate. The last two at least check that the host name in the certificate is the one you expect.
... hope you find it helpful

//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;
}

The very simple "catch all" solution is this:

System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };

Sebastian-Castaldi 的解决方案更加详细。

I personally like the following solution the most:

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的解决办法后找到了这个。

如果您不想盲目信任每个人,而只为某些主机创建信任例外,则以下解决方案更加适合。

public static class Ssl
{
    private static readonly string[] TrustedHosts = new[] {
      "host1.domain.com", 
      "host2.domain.com"
    };

    public static void EnableTrustedHosts()
    {
      ServicePointManager.ServerCertificateValidationCallback = 
      (sender, certificate, chain, errors) =>
      {
        if (errors == SslPolicyErrors.None)
        {
          return true;
        }

        var request = sender as HttpWebRequest;
        if (request != null)
        {
          return TrustedHosts.Contains(request.RequestUri.Host);
        }

        return false;
      };
    }
}

然后在你的应用程序启动时调用Ssl.EnableTrustedHosts。

If you are using Windows 2003, you can try this:

Open Microsoft Management Console (Start --> Run --> mmc.exe);

选择文件-->添加/删除控件。

在独立标签中,选择"添加";

Choose the Certificates snap-in, and click Add;

In the wizard, choose the Computer Account, and then choose Local Computer. Press Finish to end the wizard;

关闭添加/删除快捷方式对话框;

Navigate to Certificates (Local Computer) and choose a store to import:

If you have the Root CA certificate for the company that issued the certificate, choose Trusted Root Certification Authorities;

If you have the certificate for the server itself, choose Other People

Right-click the store and choose All Tasks --> Import

Follow the wizard and provide the certificate file you have;

After that, simply restart IIS and try calling the web service again.

参考:http://www.outsystems.com/NetworkForums/ViewTopic.aspx?Topic=Web-Services:-Could-not-establish-trust-relationship-for-the-SSL/TLS-...

Luke wrote a pretty good article about this .. pretty straight forward .. give this a try

Luke s Solution

Reason (quote from his article (minus cursing)) ".. The problem with the code above is that it doesn’t work if your certificate is not valid. Why would I be posting to a web page with and invalid SSL certificate? Because I’m cheap and I didn’t feel like paying Verisign or one of the other **-*s for a cert to my test box so I self signed it. When I sent the request I got a lovely exception thrown at me:

System.Net.WebException The underlying connection was closed. Could not establish trust relationship with remote server.

I don’t know about you, but to me that exception looked like something that would be caused by a silly mistake in my code that was causing the POST to fail. So I kept searching, and tweaking and doing all kinds of weird things. Only after I googled the ***n thing I found out that the default behavior after encountering an invalid SSL cert is to throw this very exception. .."

Microsoft 的 SSL 诊断工具可能能够帮助识别问题。

更新:链接现已修复。

添加此内容:

 ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;}

right before the line that you re calling the service

我刚遇到了这个问题。我的解决办法是手动同步时间服务器来更新系统时间。可以通过以下方法进行操作:

  • Right-click the clock in the task bar
  • Select Adjust Date/Time
  • Select the Internet Time tab
  • Click Change Settings
  • Select Update Now

In my case this was syncing incorrectly so I had to click it several times before it updated correctly. If it continues to update incorrectly you can even try using a different time server from the server drop-down.

试试这个:

System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12;

请注意,您必须至少使用4.5 .NET框架工作。

我在Internet Explorer中的.NET应用程序中遇到了类似的问题。

I solved the problem adding the certificate (VeriSign Class 3 certificate in my case) to trusted editors certificates.

Go to Internet Options-> Content -> Publishers and import it

如果您从以下位置导出,您可以获得证书:

Internet Options-> Content -> Certificates -> Intermediate Certification Authorities -> VeriSign Class 3 Public Primary Certification Authority - G5

谢谢 (xiè xiè)

我在与URL类似的Web服务器运行时发生了此错误:

a.b.domain.com

但是它没有证书,所以我得到了一个叫做DNS的东西。

a_b.domain.com

仅在这里提供提示,因为它在谷歌排名第一。

For those who are having this issue through a VS client side once successfully added a service reference and trying to execute the first call got this exception: “The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel” If you are using (like my case) an endpoint URL with the IP address and got this exception, then you should probably need to re-add the service reference doing this steps:

  • Open the endpoint URL on Internet Explorer.
  • Click on the certificate error (red icon in address bar)
  • Click on View certificates.
  • Grab the issued to: "name" and replace the IP address or whatever name we were using and getting the error for this "name".

Try again :). Thanks

在我的情况下,我试图在使用IIS 7的Visual Studio环境中测试SSL。

这就是我最终采取的方法使它能够工作:

  • 在我的 IIS 中,在绑定的“Bindings”部分中,我必须将 HTTPS 绑定到端口 443,并选择“ IIS Express 开发证书”。

  • 在我的站点的高级设置部分,在右侧,我不得不将“启用的协议”从“http”更改为“https”。

  • 在 SSL 设置图标下,我选择了“接受”客户端证书。

  • Then I had to recycle the app pool.

  • 我还必须使用mmc.exe将本地主机证书导入到我的个人存储中。

我的web.config文件已经正确配置,因此在我解决了以上所有问题之后,我能够继续我的测试。

我的解决方案(使用VB.Net,该应用程序的“staging”(UAT)版本需要使用“staging”证书,但不影响它们在现场站点上的请求)。

    ...
        Dim url As String = ConfigurationManager.AppSettings("APIURL") & "token"
        If url.ToLower().Contains("staging") Then
           System.Net.ServicePointManager.ServerCertificateValidationCallback = AddressOf AcceptAllCertifications
        End If
    ...

    Private  Function AcceptAllCertifications(ByVal sender As Object, ByVal certification As System.Security.Cryptography.X509Certificates.X509Certificate, ByVal chain As System.Security.Cryptography.X509Certificates.X509Chain, ByVal sslPolicyErrors As System.Net.Security.SslPolicyErrors) As Boolean
        Return True
    End Function

如果有帮助的话,我一直在使用一种变化。

来电者必须明确要求需要不受信任的认证,并在完成后将回调放回默认状态。

    /// <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;
        }
    }




相关问题
热门标签