Mono https Web 请求失败,并显示“身份验证或解密已失败”

发布于 2024-10-16 07:18:35 字数 2485 浏览 5 评论 0 原文

我正在制作一个简单的 REST 客户端以在我的 C# 应用程序中使用。在 Windows 上的 .net 中,它非常适合 http:// 和 https:// 连接。在 Ubuntu 10.10 上的 Mono 2.6.7 中(也用 2.8 进行了测试,结果相同),仅 http:// 有效。 https:// 连接在 request.GetResponse() 方法上抛出此异常:

Unhandled Exception: System.Net.WebException: Error getting response stream (Write: The authentication or decryption has failed.): SendFailure ---> System.IO.IOException: The authentication or decryption has failed. ---> Mono.Security.Protocol.Tls.TlsException: Invalid certificate received from server. Error code: 0xffffffff800b010a
  at Mono.Security.Protocol.Tls.Handshake.Client.TlsServerCertificate.validateCertificates (Mono.Security.X509.X509CertificateCollection certificates) [0x00000] in <filename unknown>:0 
  at Mono.Security.Protocol.Tls.Handshake.Client.TlsServerCertificate.ProcessAsTls1 () [0x00000] in <filename unknown>:0 
  at Mono.Security.Protocol.Tls.Handshake.HandshakeMessage.Process () [0x00000] in <filename unknown>:0 
  at (wrapper remoting-invoke-with-check) Mono.Security.Protocol.Tls.Handshake.HandshakeMessage:Process ()
  at Mono.Security.Protocol.Tls.ClientRecordProtocol.ProcessHandshakeMessage (Mono.Security.Protocol.Tls.TlsStream handMsg) [0x00000] in <filename unknown>:0 
  at Mono.Security.Protocol.Tls.RecordProtocol.InternalReceiveRecordCallback (IAsyncResult asyncResult) [0x00000] in <filename unknown>:0 
  --- End of inner exception stack trace ---
  at Mono.Security.Protocol.Tls.SslStreamBase.AsyncHandshakeCallback (IAsyncResult asyncResult) [0x00000] in <filename unknown>:0 
  --- End of inner exception stack trace ---
  at System.Net.HttpWebRequest.EndGetResponse (IAsyncResult asyncResult) [0x00000] in <filename unknown>:0 
  at System.Net.HttpWebRequest.GetResponse () [0x00000] in <filename unknown>:0 

我无法找到任何方法来解决此问题。任何人都知道为什么会发生这种情况以及如何解决它?

同样,这只在 Mono 中失败,.Net 似乎在建立连接时没有任何问题。

这是调用代码:

public JToken DoRequest(string path, params string[] parameters) {
    if(!path.StartsWith("/")) {
        path = "/" + path;
    }
    string fullUrl = url + path + ToQueryString(parameters);

    if(DebugUrls) Console.WriteLine("Requesting: {0}", fullUrl);

    WebRequest request = HttpWebRequest.CreateDefault(new Uri(fullUrl));
    using(WebResponse response = request.GetResponse())
    using(Stream responseStream = response.GetResponseStream()) {
        return ReadResponse(responseStream);
    }
}

I'm making a simple REST client to use in my C# applications. In .net on Windows It works great with http:// and https:// connections. In mono 2.6.7 (Also tested with 2.8 with the same results) on Ubuntu 10.10 only http:// works. https:// connections throw up this exception on the request.GetResponse() method:

Unhandled Exception: System.Net.WebException: Error getting response stream (Write: The authentication or decryption has failed.): SendFailure ---> System.IO.IOException: The authentication or decryption has failed. ---> Mono.Security.Protocol.Tls.TlsException: Invalid certificate received from server. Error code: 0xffffffff800b010a
  at Mono.Security.Protocol.Tls.Handshake.Client.TlsServerCertificate.validateCertificates (Mono.Security.X509.X509CertificateCollection certificates) [0x00000] in <filename unknown>:0 
  at Mono.Security.Protocol.Tls.Handshake.Client.TlsServerCertificate.ProcessAsTls1 () [0x00000] in <filename unknown>:0 
  at Mono.Security.Protocol.Tls.Handshake.HandshakeMessage.Process () [0x00000] in <filename unknown>:0 
  at (wrapper remoting-invoke-with-check) Mono.Security.Protocol.Tls.Handshake.HandshakeMessage:Process ()
  at Mono.Security.Protocol.Tls.ClientRecordProtocol.ProcessHandshakeMessage (Mono.Security.Protocol.Tls.TlsStream handMsg) [0x00000] in <filename unknown>:0 
  at Mono.Security.Protocol.Tls.RecordProtocol.InternalReceiveRecordCallback (IAsyncResult asyncResult) [0x00000] in <filename unknown>:0 
  --- End of inner exception stack trace ---
  at Mono.Security.Protocol.Tls.SslStreamBase.AsyncHandshakeCallback (IAsyncResult asyncResult) [0x00000] in <filename unknown>:0 
  --- End of inner exception stack trace ---
  at System.Net.HttpWebRequest.EndGetResponse (IAsyncResult asyncResult) [0x00000] in <filename unknown>:0 
  at System.Net.HttpWebRequest.GetResponse () [0x00000] in <filename unknown>:0 

I haven't been able to find any way to fix this. Anyone have any idea why this is happening and how to fix it?

Again, this only fails in Mono, .Net doesn't seem to have any problem establishing a connection.

here's the calling code:

public JToken DoRequest(string path, params string[] parameters) {
    if(!path.StartsWith("/")) {
        path = "/" + path;
    }
    string fullUrl = url + path + ToQueryString(parameters);

    if(DebugUrls) Console.WriteLine("Requesting: {0}", fullUrl);

    WebRequest request = HttpWebRequest.CreateDefault(new Uri(fullUrl));
    using(WebResponse response = request.GetResponse())
    using(Stream responseStream = response.GetResponseStream()) {
        return ReadResponse(responseStream);
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

安稳善良 2024-10-23 07:18:35

我对 Unity (也使用单声道)和 这篇文章帮助我解决了这个问题。

只需在提出请求之前添加以下行:

ServicePointManager.ServerCertificateValidationCallback = MyRemoteCertificateValidationCallback;

以及此方法:

public bool MyRemoteCertificateValidationCallback(System.Object sender,
    X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
    bool isOk = true;
    // If there are errors in the certificate chain,
    // look at each error to determine the cause.
    if (sslPolicyErrors != SslPolicyErrors.None) {
        for (int i=0; i<chain.ChainStatus.Length; i++) {
            if (chain.ChainStatus[i].Status == X509ChainStatusFlags.RevocationStatusUnknown) {
                continue;
            }
            chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain;
            chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
            chain.ChainPolicy.UrlRetrievalTimeout = new TimeSpan (0, 1, 0);
            chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllFlags;
            bool chainIsValid = chain.Build ((X509Certificate2)certificate);
            if (!chainIsValid) {
                isOk = false;
                break;
            }
        }
    }
    return isOk;
}

I had the same problem with Unity (which also uses mono) and this post helped me to solve it.

Just add the following line before making your request:

ServicePointManager.ServerCertificateValidationCallback = MyRemoteCertificateValidationCallback;

And this method:

public bool MyRemoteCertificateValidationCallback(System.Object sender,
    X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
    bool isOk = true;
    // If there are errors in the certificate chain,
    // look at each error to determine the cause.
    if (sslPolicyErrors != SslPolicyErrors.None) {
        for (int i=0; i<chain.ChainStatus.Length; i++) {
            if (chain.ChainStatus[i].Status == X509ChainStatusFlags.RevocationStatusUnknown) {
                continue;
            }
            chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain;
            chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
            chain.ChainPolicy.UrlRetrievalTimeout = new TimeSpan (0, 1, 0);
            chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllFlags;
            bool chainIsValid = chain.Build ((X509Certificate2)certificate);
            if (!chainIsValid) {
                isOk = false;
                break;
            }
        }
    }
    return isOk;
}
以为你会在 2024-10-23 07:18:35

Windows 上的 .NET Framework 使用 Windows 证书存储(mmc、添加/删除管理单元、证书)来确定是否接受来自远程站点的 SSL 证书。 Windows 附带了一堆根证书颁发机构和中间证书颁发机构 (CA),它们会通过 Windows Update 定期更新。因此,您的 .NET 代码通常会信任由证书存储中的 CA 或 CA 的后代颁发的证书(包括大多数信誉良好的商业 CA)。

在 Mono 中,没有 Windows 证书存储。 Mono有自己的商店。默认情况下,它是空的(没有受信任的默认 CA)。您需要自己管理条目。

请看这里:

mozroots.exe 点将使您的 Mono 安装信任 Firefox 在默认安装后信任的所有内容。

The .NET Framework on Windows uses the Windows Certificates store (mmc, Add/Remove Snap-Ins, Certificates) to determine whether to accept an SSL certificate from a remote site. Windows ships with a bunch of Root and Intermediate Certificate Authorities (CA) and they get updated periodically by Windows Update. As a result, your .NET code will generally trust a certificate provided it was issued by a CA or a descendant of a CA in the certificate store (most reputable commercial CA's are included).

In Mono, there is no Windows Certificate store. Mono has it's own store. By default, it is empty (there are no default CA's that are trusted). You need to manage the entries yourself.

Take a look here:

The mozroots.exe point will cause your mono install to trust everything that Firefox trusts after a default install.

全部不再 2024-10-23 07:18:35

在make request http请求之前写下这一行。这应该是工作。

ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback((sender, certificate, chain, policyErrors) => { return true; });


private static bool RemoteCertificateValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
    {
        //Return true if the server certificate is ok
        if (sslPolicyErrors == SslPolicyErrors.None)
            return true;

        bool acceptCertificate = true;
        string msg = "The server could not be validated for the following reason(s):\r\n";

        //The server did not present a certificate
        if ((sslPolicyErrors &
             SslPolicyErrors.RemoteCertificateNotAvailable) == SslPolicyErrors.RemoteCertificateNotAvailable)
        {
            msg = msg + "\r\n    -The server did not present a certificate.\r\n";
            acceptCertificate = false;
        }
        else
        {
            //The certificate does not match the server name
            if ((sslPolicyErrors &
                 SslPolicyErrors.RemoteCertificateNameMismatch) == SslPolicyErrors.RemoteCertificateNameMismatch)
            {
                msg = msg + "\r\n    -The certificate name does not match the authenticated name.\r\n";
                acceptCertificate = false;
            }

            //There is some other problem with the certificate
            if ((sslPolicyErrors &
                 SslPolicyErrors.RemoteCertificateChainErrors) == SslPolicyErrors.RemoteCertificateChainErrors)
            {
                foreach (X509ChainStatus item in chain.ChainStatus)
                {
                    if (item.Status != X509ChainStatusFlags.RevocationStatusUnknown &&
                        item.Status != X509ChainStatusFlags.OfflineRevocation)
                        break;

                    if (item.Status != X509ChainStatusFlags.NoError)
                    {
                        msg = msg + "\r\n    -" + item.StatusInformation;
                        acceptCertificate = false;
                    }
                }
            }
        }

        //If Validation failed, present message box
        if (acceptCertificate == false)
        {
            msg = msg + "\r\nDo you wish to override the security check?";
//          if (MessageBox.Show(msg, "Security Alert: Server could not be validated",
//                       MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1) == DialogResult.Yes)
                acceptCertificate = true;
        }

        return acceptCertificate;
    }

Write this line before make request http request. this should be work.

ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback((sender, certificate, chain, policyErrors) => { return true; });


private static bool RemoteCertificateValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
    {
        //Return true if the server certificate is ok
        if (sslPolicyErrors == SslPolicyErrors.None)
            return true;

        bool acceptCertificate = true;
        string msg = "The server could not be validated for the following reason(s):\r\n";

        //The server did not present a certificate
        if ((sslPolicyErrors &
             SslPolicyErrors.RemoteCertificateNotAvailable) == SslPolicyErrors.RemoteCertificateNotAvailable)
        {
            msg = msg + "\r\n    -The server did not present a certificate.\r\n";
            acceptCertificate = false;
        }
        else
        {
            //The certificate does not match the server name
            if ((sslPolicyErrors &
                 SslPolicyErrors.RemoteCertificateNameMismatch) == SslPolicyErrors.RemoteCertificateNameMismatch)
            {
                msg = msg + "\r\n    -The certificate name does not match the authenticated name.\r\n";
                acceptCertificate = false;
            }

            //There is some other problem with the certificate
            if ((sslPolicyErrors &
                 SslPolicyErrors.RemoteCertificateChainErrors) == SslPolicyErrors.RemoteCertificateChainErrors)
            {
                foreach (X509ChainStatus item in chain.ChainStatus)
                {
                    if (item.Status != X509ChainStatusFlags.RevocationStatusUnknown &&
                        item.Status != X509ChainStatusFlags.OfflineRevocation)
                        break;

                    if (item.Status != X509ChainStatusFlags.NoError)
                    {
                        msg = msg + "\r\n    -" + item.StatusInformation;
                        acceptCertificate = false;
                    }
                }
            }
        }

        //If Validation failed, present message box
        if (acceptCertificate == false)
        {
            msg = msg + "\r\nDo you wish to override the security check?";
//          if (MessageBox.Show(msg, "Security Alert: Server could not be validated",
//                       MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1) == DialogResult.Yes)
                acceptCertificate = true;
        }

        return acceptCertificate;
    }
作死小能手 2024-10-23 07:18:35

Mono 默认不信任任何证书,要导入 Mozilla 信任的根权限,您可以在 mozroots.exe 所在的 Mono 安装文件夹中运行 mozroots --import --quiet

Mono does not trust any certificate by default, to import the Mozilla trusted root authorities you can run mozroots --import --quiet in the mono installation folder where mozroots.exe is located

生寂 2024-10-23 07:18:35

我也有同样的问题。
当 http 响应抛出此异常时,我会这样做:

System.Diagnostics.Process.Start("mozroots","--import --quiet");

这会导入丢失的证书,并且该异常再也不会发生。

I had the same problem.
When the http response throws this exception then I do:

System.Diagnostics.Process.Start("mozroots","--import --quiet");

this imports the missing certificates and the exception never happend again.

随心而道 2024-10-23 07:18:35

Unity 的另一个解决方案是初始化 ServicePointManager 一次以始终接受证书。这可行,但显然不安全。

System.Net.ServicePointManager.ServerCertificateValidationCallback +=
           delegate (object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate,
                                   System.Security.Cryptography.X509Certificates.X509Chain chain,
                                   System.Net.Security.SslPolicyErrors sslPolicyErrors)
           {
               return true; // **** Always accept
       };

Another solution for Unity is to initialize the ServicePointManager once to always accept the certificates. This works but is obviously not secure.

System.Net.ServicePointManager.ServerCertificateValidationCallback +=
           delegate (object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate,
                                   System.Security.Cryptography.X509Certificates.X509Chain chain,
                                   System.Net.Security.SslPolicyErrors sslPolicyErrors)
           {
               return true; // **** Always accept
       };
对你而言 2024-10-23 07:18:35

我也遇到这个错误。

我尝试了 ServicePointManager.ServerCertificateValidationCallbackServicePointManager.CertificatePolicy 但仍然不起作用。

我愤怒。构建一个 cURL 包装器。这对于我的玩具项目来说效果很好。

/// <summary>
/// For MONO ssl decryption failed
/// </summary>
public static string PostString(string url, string data)
{
    Process p = null;
    try
    {
        var psi = new ProcessStartInfo
        {
            FileName = "curl",
            Arguments = string.Format("-k {0} --data \"{1}\"", url, data),
            RedirectStandardOutput = true,
            UseShellExecute = false,
            CreateNoWindow = false,
        };

        p = Process.Start(psi);

        return p.StandardOutput.ReadToEnd();
    }
    finally
    {
        if (p != null && p.HasExited == false)
            p.Kill();
    }
}

I encounter the error too.

I tryied ServicePointManager.ServerCertificateValidationCallback and ServicePointManager.CertificatePolicy but still not work.

I anger. build a cURL wraper. It's work fine for my toy project.

/// <summary>
/// For MONO ssl decryption failed
/// </summary>
public static string PostString(string url, string data)
{
    Process p = null;
    try
    {
        var psi = new ProcessStartInfo
        {
            FileName = "curl",
            Arguments = string.Format("-k {0} --data \"{1}\"", url, data),
            RedirectStandardOutput = true,
            UseShellExecute = false,
            CreateNoWindow = false,
        };

        p = Process.Start(psi);

        return p.StandardOutput.ReadToEnd();
    }
    finally
    {
        if (p != null && p.HasExited == false)
            p.Kill();
    }
}
撩人痒 2024-10-23 07:18:35

第一个答案已经说明了这一点:Windows 之外的任何其他平台上的 Mono 都没有附带任何内容,因此最初它不信任任何证书。那么该怎么办呢?

这是一篇很好的文章,介绍了从开发人员的角度处理问题的不同方法:
http://www.mono-project.com/archived/usingtrustedrootsrespectively/

简短摘要:
您可以:

  • 忽略安全问题
  • 忽略问题
  • 让用户知道并中止
  • 让用户知道并让他/她选择继续,风险自负

上面的链接附带了每种情况的代码示例。

The first answer says it already: Mono on anything other than Windows doesn’t come with anything so initially it doesn’t trust any certificate. So what to do?

Here is a nice article about different ways to deal with the problem from the developer’s perspective:
http://www.mono-project.com/archived/usingtrustedrootsrespectfully/

Short summary:
You can either:

  • ignore the security concern
  • ignore the problem
  • let the user know and abort
  • let the user know and give him/her a choice to continue at own risk

The above link comes with code examples for each case.

手心的温暖 2024-10-23 07:18:35

按照接受的答案导入证书后,我仍然遇到这个问题。

我发现 Mono 4.8 中添加了 对 TLS 1.2 的支持。 0 使用 Google 的 BoringSSL,并且我使用的 Mono 版本早于这。我更新到 Mono 5.10,现在可以连接而不会收到此异常。

I was still having this problem after importing the certificates as per the accepted answer.

I found that support for TLS 1.2 was added in Mono 4.8.0 which uses Google's BoringSSL, and that I was using a version of Mono older than this. I updated to Mono 5.10 and can now connect without receiving this exception.

一袭白衣梦中忆 2024-10-23 07:18:35

您可以在 iOS 构建中设置 Mono TLS 实现,一切都会正常工作,如下所述:http://massivepixel.co/blog/post/xamarin-studio-6-certificate-unknown(尽管 Mono TLS 不支持较新版本的 TLS,但我还没有遇到过这样的问题:是一个问题)。

You can set Mono TLS implementation in iOS Build and everything will work fine as described here: http://massivepixel.co/blog/post/xamarin-studio-6-certificate-unknown (though Mono TLS doesn't support newer versions of TLS but I haven't yet bumped on the issue that it is a problem).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文