WCF - сертификат не настроен должным образом с HTTP.SYS в случае HTTPS.Работает с прокси Чарльза - PullRequest
0 голосов
/ 08 июня 2018

Это, похоже, распространенная ошибка (есть другие посты с похожими проблемами) - однако я просмотрел все эти посты и статьи MSDN (https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/working-with-certificates).Сценарий: попытка получить доступ к службе с помощью конечной точки HTTPS.Установка сертификата клиента в коде (сертификат загружается правильно).Что касается сертификата сервера, я пробовал оба варианта ниже:*

Я импортировал сертификат сервера в Личное, а также в машинное хранилище (центры / сертификаты Trusted Root).Странно то, что вызов проходит, когда я использую Charles Proxy в качестве SSL-прокси.Другие настройки:

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

    ServicePointManager.ServerCertificateValidationCallback +=
            (se, cert, chain, sslerror) =>
            {
                //Console.WriteLine(cert.GetCertHashString());

                if (cert.GetCertHashString() == "[actual hash here]")
                    return true;
                else
                    return false;
            };

Приведенная выше проверка хеша работает нормально, когда работает прокси-сервер Charles.Без прокси-сервера обратный вызов даже не вызывается.

Любая обратная связь приветствуется.

(Возможно, стоит отметить, что Java-клиент, использующий библиотеку Apache CXF, работает нормально - для той же службы.)

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

1 Ответ

0 голосов
/ 14 июня 2018

ОК, после нескольких дней (и ночей) ударов головой, мои размышления / выводы (и, конечно, решение!) Следующие:

  • Есть «SSL», а затеместь SSLv2, SSLv3, TLSv1.0, TLSv1.1, TLS1.2 и TLSv1.3 (черновик на данный момент).

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

  • Ошибка HTTP.SYS, по-видимому, является результатом того, что клиент не может договориться с сервером о соответствующей версии.Проходя через прокси Чарльза, было ясно, что и Чарльз, и служба, на которую мы пытались попасть, использовали TLSV1.1.

  • В моем случае я использовал wsHTTPBinding и хотя япопытался установить System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;и другие комбинации, я никогда не мог получить ошибку HTTP.SYS, чтобы уйти.Казалось бы, сервер и клиент никогда не смогут выбрать версию, с которой они могли бы согласиться.

  • Я попытался использовать другие привязки, такие как basicHttpBinding (с TransportWithMessageCredential), а также basicHttpsBinding,но безрезультатно.Более того, с некоторыми незначительными изменениями в элементах привязки (через config и код) в каждом случае я закончил с одинаковой конфигурацией привязки во всех 3 случаях (привязки basicHttp / basichHttps / wsHttp)!По сути, хотя существуют эти готовые привязки, они, вероятно, работают для самых простых сценариев.Более того, вероятно, нет необходимости в таком количестве предварительно упакованных привязок, тем более что они, похоже, используют в основном одни и те же элементы привязки.

  • Я помню, что читал, что использование пользовательского связывания лучше во многих случаях - но я думал, что, настроив wsHttpBinding, я достигну того же самого.Похоже, нет - поскольку в этой привязке есть некоторые жестко заданные свойства (например, протоколы SSL по умолчанию), которые, похоже, трудно обойти.Я взглянул на исходный код wsHttpBinding и его базовый класс, но не смог найти точное жестко закодированное местоположение (но в коде System.ServiceModel есть ссылки на протоколы «по умолчанию»).

    • В итоге у меня сработало «CustomBinding», настроенное так:

Настраиваемая конфигурация привязки - Извините, что добавили это как изображение -как форматирование на SO подыгрывало.

  • Идея состоит в том, чтобы использовать httpsTransport с requireClientCertificate, защиту с authenticationMode="CertificateOverTransport" & includeTimestamp="true" (для нашей службы требуется метка времени) и соответствующую messageSecurityVersion - в нашем случае это было: WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10.

  • Указанные выше конфигурации также автоматически подписывают метку времени.

  • Вдобавок к этому нам пришлось включить учетные данные имени пользователя / пароля,Простая установка client.ClientCredentials.UserName.UserName & client.ClientCredentials.UserName.Password не привела к тому, что эти учетные данные были включены в заголовок Security.Логика заключалась в том, чтобы добавить имя пользователя «токен», например, так:

    //Get the current binding 
    System.ServiceModel.Channels.Binding binding = client.Endpoint.Binding;
    
    //Get the binding elements 
    BindingElementCollection elements = binding.CreateBindingElements();
    
    //Locate the Security binding element
    SecurityBindingElement security = elements.Find<SecurityBindingElement>();
    
    //This should not be null - as we are using Certificate authentication anyway
    if (security != null)
    {
        UserNameSecurityTokenParameters uTokenParams = new UserNameSecurityTokenParameters();
            uTokenParams.InclusionMode = SecurityTokenInclusionMode.AlwaysToRecipient;
        security.EndpointSupportingTokenParameters.SignedEncrypted.Add(uTokenParams);
    }
    
    client.Endpoint.Binding = new CustomBinding(elements.ToArray());
    
  • Со всей этой настройкой я смог, наконец, нажать Сервис и фактически получить результат -Ну, почти !- как результат, не включает метку времени, которую WCF выдает как исключение.Это еще одна проблема, которую нужно решить.

Надеемся, читатели найдут это полезным.

Обновление:

  • Сейчаспроблема с отметкой времени также «отсортирована».Дело в том, что в ответе отсутствовал какой-либо заголовок безопасности, а не только временная метка.К счастью, был простой способ уведомить WCF об игнорировании небезопасных ответов, просто пометив атрибут на элементе безопасности: enableUnsecuredResponse = "true".Очевидно, что это нежелательно, но, поскольку у нас нет никакого контроля над сервисом, это лучшее, что мы можем сделать на данный момент.
...