Моно запросы WebRequest по HTTPS выдает "проверка подлинности или дешифрования не удалось"
Я делаю простой клиент REST для использования в моих приложениях C#. В .net на Windows он отлично работает с http:// и https: / / соединений. В mono 2.6.7 (также протестирован с 2.8 с теми же результатами) на Ubuntu 10.10 работает только http://. https: / / соединения выдают это исключение по запросу.Метод 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);
}
}
10 ответов:
Mono не доверяет никакому сертификату по умолчанию, чтобы импортировать Доверенные корневые центры Mozilla, вы можете запустить
mozroots --import --quiet
в папке установки mono, где mozroots.exe находится
у меня была такая же проблема с Unity (который также использует mono) и этот пост помог мне решить эту проблему.
просто добавьте следующую строку прежде чем сделать свой запрос:
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; }
платформа .NET Framework в Windows использует хранилище сертификатов Windows (mmc, Add/Remove Snap-Ins, Certificates), чтобы определить, следует ли принимать сертификат SSL с удаленного сайта. Windows поставляется с кучей корневых и промежуточных центров сертификации (CA), и они периодически обновляются центром обновления Windows. В результате ваш .NET-код обычно будет доверять сертификату, если он был выпущен центром сертификации или потомком центра сертификации в хранилище сертификатов (наиболее авторитетные коммерческие ЦС включены).
в Mono нет хранилища сертификатов Windows. Моно имеет свой собственный магазин. По умолчанию он пуст (нет доверенных ЦС по умолчанию). Вы должны управлять записями самостоятельно.
посмотреть здесь:
- 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 point заставит вашу моно-установку доверять всему, что 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
но все равно не работает.Я гнев. построить завиток обертки. Это прекрасно работает для моего игрушечного проекта.
/// <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-ответ выдает это исключение, я делаю:
System.Diagnostics.Process.Start("mozroots","--import --quiet");
это импортирует отсутствующие сертификаты и исключение никогда не произойдет снова.
первый ответ уже говорит об этом: Mono ни на что, кроме Windows, не поставляется ни с чем, поэтому изначально он не доверяет никакому сертификату. Так что же делать?
вот хорошая статья о различных способах решения проблемы с точки зрения разработчика : http://www.mono-project.com/archived/usingtrustedrootsrespectfully/
краткий итог описания: Вы можете либо:
- игнорировать проблемы безопасности
- игнорировать проблема
- дайте пользователю знать и прервать
- позволить пользователю знать, и дать ему выбор-продолжить на свой страх и риск
по ссылке выше поставляется с примерами кода для каждого случая.
другое решение для 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 };
вы можете установить реализацию Mono TLS в сборке iOS, и все будет работать нормально, как описано здесь:http://massivepixel.co/blog/post/xamarin-studio-6-certificate-unknown (хотя Mono TLS не поддерживает более новые версии TLS, но я еще не столкнулся с проблемой, что это проблема).
У меня все еще была эта проблема после импорта сертификатов в соответствии с принятым ответом.
Я нашел это поддержка TLS 1.2 была добавлена в Mono 4.8.0 который использует Google BoringSSL, и что я использовал версию Mono старше этого. Я обновился до Mono 5.10 и теперь могу подключиться без получения этого исключения.