单声道https webrequest失败,“validation或解密失败”
我正在做一个简单的REST客户端来使用我的C#应用程序。 在Windows上的.net上使用http://和https://连接很有效。 在单声道2.6.7(也用2.8testing,相同的结果)在Ubuntu 10.10只有http://的作品。 https://连接在request.GetResponse()方法上引发此exception:
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
我一直无法find解决这个问题的方法。 任何人都有任何想法为什么发生这种情况,以及如何解决它?
同样,这只在单声道失败,.net似乎没有任何问题build立连接。
这里是调用代码:
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); } }
我有同样的问题(也使用单声道), 这个post帮助我解决它。
在提出请求之前,只需添加以下行:
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; }
Windows上的.NET Framework使用Windows证书存储(mmc,添加/删除pipe理单元,证书)来确定是否接受来自远程站点的SSL证书。 Windows附带一系列根证书颁发机构(CA),并且通过Windows Update定期更新。 因此,如果您的.NET代码是由CA或证书存储中的CA的后代(包括大多数信誉良好的商业CA)颁发的,则它们通常会信任一个证书。
在Mono中,没有Windows证书存储。 单声道有它自己的商店。 默认情况下,它是空的(没有可信任的默认CA)。 你需要自己pipe理条目。
看看这里:
- http://www.mono-project.com/FAQ:_Security
- https://raw.github.com/mono/mono/master/mcs/class/Mono.Security/Test/tools/tlstest/tlstest.cs
mozroots.exe点将导致您的单声道安装信任默认安装后,Firefox信任的所有内容。
在请求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; }
我也遇到错误。
我尝试了ServicePointManager.ServerCertificateValidationCallback
和ServicePointManager.CertificatePolicy
但仍然无法正常工作。
我愤怒。 build立一个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(); } }
我有同样的问题。 当http响应抛出这个exception,然后我做:
System.Diagnostics.Process.Start("mozroots","--import --quiet");
这导入缺less的证书和例外从未再发生。
第一个答案已经说明了:除了Windows以外的其他任何东西都不带任何东西,所以最初它不相信任何证书。 那么该怎么办?
这里是一个很好的文章,从开发者的angular度来看待不同的方式来处理这个问题: http : //www.mono-project.com/archived/usingtrustedrootsrespectfully/
简短摘要:您可以:
- 忽视安全问题
- 忽略问题
- 让用户知道并中止
- 让用户知道并给他/她一个select继续自己的风险
上面的链接带有每个案例的代码示例。
Unity的另一个解决scheme是初始化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 };
你可以在iOS Build中设置Mono TLS实现,一切工作都会正常,如下所述: http : //massivepixel.co/blog/post/xamarin-studio-6-certificate-unknown (尽pipeMono TLS不支持更新版本的TLS,但我还没有碰到问题,这是一个问题)。