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

326

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

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

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

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

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

Роб Шрипсема
источник
В моем случае эта ошибка была вызвана переадресацией IP-адреса.
ЦСП

Ответы:

166

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

  • у вас есть DNS и прямой видимости на сервер?
  • вы используете правильное имя из сертификата?
  • сертификат еще действителен?
  • плохо настроен балансировщик нагрузки?
  • правильно ли настроены часы на новом сервере (т. е. чтобы время UTC было правильным [игнорировать местное время, оно в значительной степени бесполезно]) - это, безусловно, имеет значение для WCF, поэтому может повлиять на обычный SOAP?
  • существует ли проблема цепочки доверия сертификата? если вы переходите с сервера на мыльный сервис, можете ли вы получить SSL?
  • связано с вышеизложенным - был ли сертификат установлен в правильном месте? (вам может потребоваться копия в доверенных корневых центрах сертификации)
  • правильно ли настроен прокси-сервер на уровне машины? (который отличается от прокси пользователя); см. proxycfg для XP / 2003 (не уверен насчет Vista и т. д.)
Марк Гравелл
источник
2
1) Веб-сервис находится в Интернете. Мы можем просматривать его через браузер. 2) Новая машина - это не сервер - это рабочий стол с моим приложением, который собирает информацию о заказе и загружает ее через службу SOAP. 3) Да, мы можем перейти к ней. 4) Это новое для меня: машина уровня прокси?
Роб Шрипсема
2
Да; код не использует настройки прокси IE; он использует отдельное хранилище ... важно, чтобы это было настроено (если вы используете прокси). В XP самый простой вариант (IIRC) «proxycfg -i» для импорта настроек IE.
Марк Гравелл
11
Спасибо Марк. Это помогло мне, и проблема заключалась в том, что на сервере был сертификат, подписанный сторонним центром сертификации, которому я еще не доверял. Решением было добавить этот ЦС в список доверенных корневых ЦС.
p.campbell
1
Компьютер, на котором возникло это исключение, не смог синхронизировать системное время с использованием серверов времени. Я должен был войти и вручную синхронизировать время, прежде чем это сработало.
Крис - Haddox Technologies
4
Вы можете получить это, если вы использовали Fiddler для отладки вызовов службы и использовали режим перехвата сертификатов. Просто удалите перехват в настройках скрипача и у вас все получится
Раскин
363

Следующие фрагменты исправят ситуацию, когда что-то не так с сертификатом 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 = cert.Subject.Contains("YourServerName");
    return result;
}
Себастьян Кастальди
источник
6
Мой опыт работы с ServicePointManager. Любые изменения могут повлиять на весь домен приложения. Хотя в ответе очень четко объясняется, как это можно применить, я бы хотел остановиться на этом.
Амзат
Настройка обратного вызова для меня работает в .NET 4.5, но не в .NET 4.6
RJB
@Amzath Какие-либо предложения о том, как сбросить это после выполнения определенного запроса? Человеку может потребоваться сделать один запрос к несертифицированному серверу, а затем вернуть вещи такими, какими они были.
Исаак Лиман
1
@ Исаак Лиман: ServicePointManager.ServerCertificateValidationCallback = null;должен вернуться к поведению по умолчанию.
Майк Чемберлен
1
@MikeChamberlain Единственная проблема с вашим предложением состоит в том, что одновременные запросы могут быть небезопасными, поскольку вы работаете с глобальными настройками приложения.
Исаак Лиман,
178

Очень простое решение «поймать все» заключается в следующем:

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

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

Remy
источник
21
Я просто поместил это в #If CONFIG = "Debug"утверждение, чтобы оно активировалось только в режиме отладки. Работает отлично!
cjbarth
1
Детали могут быть хорошими, но есть что сказать и о быстрой, короткой и простой строке кода. Этот код короткий и делает свое дело.
allen1
будет ли это действовать только на текущее действие (например, используется ASP MVC)? или он будет установлен как поведение по умолчанию для приложения ASP.NET?
JeeShen Lee
2
Это следует использовать только для целей тестирования, это решение доверяет любым сертификатам, даже недействительным / просроченным
Shenron
1
Как объяснено в комментариях выше, это не проверяет, является ли соединение SSL действительным больше. Таким образом, связь между вашей системой и другими системами может быть нарушена. Это всегда вопрос того, для чего вам это нужно.
Реми
35

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

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

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

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

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

cusman
источник
4
Посмотрите ответ Себастьяна Кастальди для предостережений безопасности к этому подходу.
Эдвард Брей
Каков риск безопасности при использовании этого в производстве?
Амжад
@ Угроза безопасности заключается в том, что она полностью обходит любые преимущества использования SSL / TLS. Сервер может представить любой сертификат, который ему нравится, и этот код будет игнорировать ошибку
1800 ИНФОРМАЦИЯ
18

Если вы используете 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- ...

Диого
источник
2
Это помогло мне пройти путь, но мне нужно было иметь сертификат в разделе «Надежные корневые центры сертификации», чтобы он работал. Согласно blogs.msdn.com/b/jpsanders/archive/2009/09/16/…
Джейкоб Эвальд,
17

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

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

Грегор Славец
источник
@ thelem Да, перечитывание. Я думаю, что я неправильно прочитал первый раз
Шив
Каков риск безопасности доверять всем сертификатам в производстве?
Амжад
@ Угроза безопасности заключается в том, что любой человек между клиентом и сервером может вставить себя в центр обмена данными, использовать собственный сертификат SSL и считывать весь трафик между клиентом и сервером. Это фактически делает недействительным SSL.
Роб Проуз
Должно ли это работать, когда я использую WCF addon для генерации классов из wsdl?
Камил
7

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

Решение Люка

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

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

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

Hans
источник
1
Это решение устарело для .Net 4.5. Если вы просто хотите принять все сертификаты, см. Себастьян Кастальди или мой ответ ниже.
Реми
7

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

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

sipwiz
источник
7
На сегодняшний день (август 2012 г.) эта ссылка теперь не работает.
ashes999
Произведен поиск в каталоге загрузки, и средство диагностики SSL больше не доступно. :(
SASS_Shooter
2
Давайте исправим ссылку. Поправьте
Amzath
3

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

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

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

Крис - Haddox Technologies
источник
СВЯТАЯ КОРОВА. Пробежал чмок в эту точную вещь. Спасибо за легкое исправление!
TheGerm
3

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

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

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

Мануэль Ролдан
источник
3

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

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

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

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

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

Спасибо

debiasej
источник
1

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

a.b.domain.com

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

a_b.domain.com

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

Томас Коэль
источник
В моем случае веб-сайт был настроен с использованием подстановочного сертификата ssl (* .abcd.com). При настройке привязка сайта была похожа на xyz-abcd.com, которая вызывала проблему.
Sree
1

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

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

Попробуй еще раз :). Спасибо

Эрнест
источник
0

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

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

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

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

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

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

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

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

Попо
источник
как был настроен ваш web.config?
Chazt3n
@ Chazt3n Я не могу вам сказать, это было некоторое время назад, но это была бы базовая настройка http-привязки, я обычно использую svcutil для генерации информации о конфигурации для информации о клиенте веб-службы.
Popo
0

Мое решение (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
GreenRock
источник
-3

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

Роберто Гата
источник
Вы никогда не должны отключать проверку сертификата. Вместо этого исправьте проблему, вызывающую сбой проверки.
Дан
Каков риск безопасности при использовании этого в производстве?
Амжад