Не удалось установить доверительные отношения для безопасного канала SSL/TLS - SOAP

У меня есть простой вызов веб-службы, сгенерированный приложением Windows.NET (C#) 2.0, через прокси-сервер веб-службы, сгенерированный Visual Studio, для веб-службы, также написанной на C# (2.0). Это работало в течение нескольких лет, и продолжает делать это в дюжине или около того местах, где он работает.

Новая установка на новом сайте сталкивается с проблемой. При попытке вызвать веб-сервис происходит сбой с сообщением:

Не удалось установить доверительные отношения для безопасного канала SSL/TLS

В URL-адресе веб-службы используется SSL (https://), но это уже давно работает (и продолжает это делать) из многих других мест.

Куда я смотрю? Может ли это быть проблемой безопасности между Windows и.NET, которая уникальна для этой установки? Если да, то где мне установить доверительные отношения? Я потерялся!

20 ответов

Решение

Мысли (основанные на боли в прошлом):

  • у вас есть DNS и прямой видимости на сервер?
  • вы используете правильное имя из сертификата?
  • сертификат еще действителен?
  • плохо настроен балансировщик нагрузки?
  • правильно ли настроены часы на новом сервере (т. е. чтобы время в формате UTC было правильным [игнорировать местное время, оно в значительной степени нерелевантно]) - это, безусловно, важно для WCF, поэтому может повлиять на обычный SOAP?
  • Есть ли проблема цепочки доверия сертификатов? если вы переходите с сервера на мыльный сервис, можете ли вы получить SSL?
  • связано с вышеизложенным - был ли сертификат установлен в правильном месте? (вам может понадобиться копия в доверенных корневых центрах сертификации)
  • правильно ли настроен прокси-сервер на уровне машины? (который отличается от прокси пользователя); см. proxycfg для XP / 2003 (не уверен насчет Vista и т. д.)

Следующие фрагменты исправят ситуацию, когда что-то не так с сертификатом SSL на сервере, который вы вызываете. Например, он может быть самоподписанным или имя хоста между сертификатом и сервером может не совпадать.

Это опасно, если вы вызываете сервер, находящийся вне вашего прямого контроля, поскольку вы больше не можете быть уверены, что разговариваете с сервером, к которому, по вашему мнению, вы подключены. Однако, если вы имеете дело с внутренними серверами и получение "правильного" сертификата нецелесообразно, используйте следующее, чтобы сообщить веб-службе, что нужно игнорировать проблемы с сертификатом и отважно идти дальше.

Первые два используют лямбда-выражения, третье использует обычный код. Первый принимает любой сертификат. Последние два по крайней мере проверяют, что имя хоста в сертификате - то, которое вы ожидаете.
... надеюсь, вы найдете это полезным

//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 = false;
    if (cert.Subject.ToUpper().Contains("YourServerName"))
    {
        result = true;
    }

    return result;
}

Очень простое решение "поймай все" таково:

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

Решение от Себастьяна-Кастальди немного более детально.

Мне лично больше всего нравится следующее решение:

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

... затем, прежде чем запрашивать ошибку, сделайте следующее

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

Обнаружил это после консультации с Люком

Если вы не хотите слепо доверять всем и делать исключение доверия только для определенных хостов, то более подходящим является следующее решение.

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 при запуске вашего приложения.

Если вы используете Windows 2003, вы можете попробовать это:

Откройте консоль управления Microsoft (Пуск -> Выполнить -> mmc.exe);

Выберите "Файл" -> "Добавить / удалить оснастку";

На вкладке "Автономный" выберите "Добавить";

Выберите оснастку "Сертификаты" и нажмите "Добавить";

В мастере выберите учетную запись компьютера, а затем выберите "Локальный компьютер". Нажмите Finish, чтобы завершить работу мастера;

Закройте диалоговое окно "Добавить / удалить оснастку";

Перейдите к сертификатам (локальный компьютер) и выберите магазин для импорта:

Если у вас есть сертификат корневого центра сертификации для компании, выдавшей сертификат, выберите "Доверенные корневые центры сертификации";

Если у вас есть сертификат для самого сервера, выберите Other People

Щелкните правой кнопкой мыши магазин и выберите "Все задачи" -> "Импорт".

Следуйте указаниям мастера и предоставьте файл сертификата, который у вас есть;

После этого просто перезапустите IIS и попробуйте снова вызвать веб-сервис.

Ссылка: http://www.outsystems.com/NetworkForums/ViewTopic.aspx?Topic=Web-Services:-Could-not-establish-trust-relationship-for-the-SSL/TLS-...

Люк написал довольно хорошую статью об этом.. довольно прямо вперед.. попробуйте

Решение Люка

Причина (цитата из его статьи (минус ругань)) ".. Проблема с кодом выше в том, что он не работает, если ваш сертификат недействителен. Почему я должен публиковать на веб-странице с недействительным сертификатом SSL? Потому что Я дешевый, и мне не хотелось платить Verisign или одному из других ** - * s за сертификат для моей тестовой коробки, поэтому я сам подписал его. Когда я отправил запрос, меня бросили в прекрасное исключение:

System.Net.WebException Базовое соединение было закрыто. Не удалось установить доверительные отношения с удаленным сервером.

Я не знаю о вас, но для меня это исключение выглядело как нечто, что было бы вызвано глупой ошибкой в ​​моем коде, которая приводила к сбою POST. Поэтому я продолжал искать, настраивать и делать разные странные вещи. Только после того, как я погуглил дерьмовую вещь, я обнаружил, что поведение по умолчанию после обнаружения недействительного сертификата SSL - это исключение. .."

Средство диагностики SSL от Microsoft может помочь выявить проблему.

ОБНОВЛЕНИЕ ссылка была исправлена.

Добавь это:

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

прямо перед линией, по которой вы звоните в службу

Попробуй это:

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

Обратите внимание, что вы должны работать как минимум с 4.5 .NET Framework

Я только что столкнулся с этой проблемой. Я решил обновить системное время, вручную синхронизировавшись с серверами времени. Для этого вы можете:

  • Щелкните правой кнопкой мыши часы на панели задач
  • Выбрать Adjust Date/Time
  • Выберите Internet Time табуляция
  • Нажмите Change Settings
  • Выбрать Update Now

В моем случае это было синхронизировано неправильно, поэтому мне пришлось щелкнуть несколько раз, прежде чем он обновился правильно. Если он продолжает обновляться некорректно, вы можете даже попробовать использовать другой сервер времени из выпадающего списка.

У меня была похожая проблема в .NET приложение в Internet Explorer.

Я решил проблему с добавлением сертификата (сертификат VeriSign Class 3 в моем случае) к сертификатам доверенных редакторов.

Перейдите в Свойства обозревателя-> Содержание -> Издатели и импортируйте его

Вы можете получить сертификат, если экспортируете его из:

Свойства обозревателя-> Содержимое -> Сертификаты -> Промежуточные центры сертификации -> Общий первичный центр сертификации VeriSign класса 3 - G5

У меня была эта ошибка при запуске веб-сервера с URL-адресом, как:

a.b.domain.com

но для него не было сертификата, поэтому я получил DNS под названием

a_b.domain.com

Просто поместите подсказку к этому решению здесь, так как это заняло первое место в Google.

Для тех, кто столкнулся с этой проблемой через клиентскую сторону VS, однажды успешно добавил ссылку на службу и попытался выполнить первый вызов, получил следующее исключение: "Базовое соединение было закрыто: не удалось установить доверительные отношения для безопасного канала SSL/TLS". Если вы используете (как и в моем случае) URL-адрес конечной точки с IP-адресом и получили это исключение, тогда вам, вероятно, потребуется повторно добавить ссылку на службу, выполнив следующие действия:

  • Откройте URL-адрес конечной точки в Internet Explorer.
  • Нажмите на ошибку сертификата (красный значок в адресной строке)
  • Нажмите на Просмотр сертификатов.
  • Возьмите выданное имя: "имя" и замените IP-адрес или любое другое имя, которое мы использовали, и получим ошибку для этого "имени".

Попробуйте снова:). Спасибо

На самом деле эта проблема связана с выпуском сертификата SSL/TLS, поэтому вы можете найти проблему, используя следующий код:

Вот лучшее решение https://indiabix.info/id/16/the-underlying-conne

Для меня все вышеперечисленное не сработало. Что действительно работало, так это следующее:

Измените настройки прокси-сервера Visual Studio в

C:\Program Files (x86)[версия VisualStudio]\Common7\IDE\devenv.exe.config

к

      <system.net>
   <defaultProxy useDefaultCredentials="true" enabled="true">
     <proxy usesystemdefault="True" />
   </defaultProxy>
   <settings>
     <ipv6 enabled="true"/>
   </settings>
</system.net>

В моем случае я пытался проверить SSL в моей среде Visual Studio, используя IIS 7.

Вот что я сделал, чтобы заставить его работать:

  • Под моим сайтом в разделе "Привязки..." справа в IIS мне пришлось добавить привязку "https" к порту 443 и выбрать "Сертификат разработки IIS Express".

  • Под моим сайтом в разделе "Расширенные настройки..." справа мне пришлось изменить "Активированные протоколы" с "http" на "https".

  • Под значком "Настройки SSL" я выбрал "Принять" для клиентских сертификатов.

  • Затем мне пришлось утилизировать пул приложений.

  • Мне также пришлось импортировать сертификат локального хоста в мой личный магазин, используя mmc.exe.

мой web.config файл уже настроен правильно, поэтому после того, как я разобрался со всем вышеперечисленным, я смог продолжить тестирование.

Вариант, который я использую некоторое время, если кому-то помогает.

Вызывающий должен явно запросить, что требуются ненадежные сертификаты, и вернуть обратный вызов в состояние по умолчанию после завершения.

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

Мое решение (VB.Net, "промежуточная" (UAT) версия этого приложения должна работать с "промежуточным" сертификатом, но не влиять на запросы, когда они находятся на действующем сайте):

    ...
        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

Если не работает плохой сертификат, когда 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 работает очень хорошо

Другие вопросы по тегам