Сертификат службы WCF и идентификатор конечной точки клиентской стороны - почему он не работает?

[Обновление]. Я также добавляю полные конфигурационные файлы для service, а для клиент (вне этого, чтобы не заливать тему)

У меня ситуация довольно похожа на ситуацию, описанную в этом, однако мой вопрос несколько иной.

  • Я использую NetTcpBinding с безопасностью установить в TransportWithMessageCredential
  • Я использую пароль/имя пользователя учетные данные, поддерживаемые ASP.NET провайдер
  • Мой сервис находится в Windows Сервис
  • У меня do есть поведение моей конечной точки заданная проверка revocationMode = "NOCHECK"

Требуется, чтобы служба предоставляла сертификат для аутентификации клиентам. Это нормально, я просто делаю:

<serviceCertificate findValue="***"
                    storeLocation="CurrentUser"
                    storeName="My"
                    x509FindType="FindByThumbprint"/>

Теперь я несколько подумал, что теперь клиент будет иметь

<identity>
  <certificate encodedValue="encoded certificate"/>
</identity>

И он сможет проверить учетные данные службы , не установив этот сертификат в хранилище на клиентской машине.

Я был удивлен чтобы узнать, что, хотя я установил учетные данные службы для сертификата, WSDL предоставляет

<Identity>
   <Dns>Foo</Dns>
</Identity>

Опять же, при обслуживании я могу установить Identity в CertificateReference и подключить его к одному и тому же сертификату, а затем WSDL будет выставлять личность как X509Certificate, но когда я запускаю клиент, этот параметр игнорируется, и я получаю сообщение об ошибке:

System.ServiceModel.Security.SecurityNegotiationException: Сертификат X.509 CN = xxx отсутствует в доверенные люди хранят. X.509 сертификат CN = xxx строительство цепочки не смогли. Сертификат, который был использован имеет цепочку доверия, которая не может быть проверено. Заменить сертификат или измените сертификатValidationMode. Обработана цепочка сертификатов, но завершено в корневом сертификате, который не доверяет поставщик доверия.

Есть ли способ заставить клиента использовать это значение из конфигурации и работы без необходимости установки сертификата службы (или его корня) на машине клиента?

[ОБНОВЛЕНИЕ] Пока значение параметра certificateValidationMode не будет отменено, исключение будет исключено, это неприемлемое решение с точки зрения безопасности.

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

Ответ 1

Эскиз решения:

1) Определите и зарегистрируйте пользовательский X509CertificateValidator на клиенте

2) В методе Подтвердить сравните данный сертификат с тем, который присутствует в объекте EndpointAddress.Identity. Объект, на который ссылается это свойство, должен иметь точный тип X509CertificateEndpointIdentity.

Я не тестировал это решение, но это имеет для меня смысл.

НТН Педро

Ответ 2

[ОБНОВЛЕНИЕ] При установке certificateValidationMode никому не будет исключить исключение, неприемлемое решение безопасности точки зрения.

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

Вы ошибаетесь. Это будет отлично. Это на самом деле то, что вы хотите - ваш сертификат не должен быть проверен. Все, что вам нужно, - установить личность конечной точки на клиенте на

<identity>
  <certificate encodedValue="encoded certificate"/>
</identity>

Когда клиент подключается к серверу, WCF будет сравнивать два сертификата и выдавать исключение, если они не совпадают. И вы совершенно безопасны.

Использование специального валидатора, такого как Педро Феликс, предлагается в вашем случае совершенно ненужно. Именно это означает тождество конечной точки.

Ответ 3

Извините, я не могу комментировать другие ответы.

Я только что протестировал это в .NET 4.0, и я могу подтвердить, что ответ "Зератул" верен. Явно настраивает идентификатор службы либо в конфигурации, либо программно достаточно для аутентификации сервера. Нет необходимости проверять сертификат другими способами (т.е. Вы можете установить "certificateValidationMode" на "None" ), поскольку вы используете метод окончательной проверки - сравнение отпечатка сертификата.

@AlexDrenea

"serviceCertificate" не используется для проверки. Он используется с защитой сообщений для шифрования сообщений до их отправки на сервер. См. Документацию по этому вопросу в Microsoft:

http://msdn.microsoft.com/en-us/library/ms731782.aspx

Ответ 4

Это дополнительный комментарий к моему предыдущему ответу. Извините, я не могу комментировать ответы.

Кроме того, вам нужно не установить на сервере любую. Забудьте о том, что WSDL сообщает вам о личности сервера. Идентификация конечной точки удаленного сервиса определяется клиентом во время выполнения. Если сервер использует SSL, он имеет несколько идентификаторов: общее имя сертификата (то есть идентификатор DNS), идентификатор сертификата и идентификатор RSA (не уверен в последнем). Таким образом, вы можете проверить идентификатор сервера любым из этих критериев (или несколькими из них).

Ответ 5

Вы зависите и почти закончили настройку конфигурации клиента. Вам не хватает последней информации (как указано в описании ошибки): вам нужно установить для параметра revocationMode значение NoCheck в конфигурации:

 <behaviors>
  <endpointBehaviors>
    <behavior name="SecureMessageUserName">
      <clientCredentials>
         <serviceCertificate>
            <authentication revocationMode="NoCheck"/>
         </serviceCertificate>
      </clientCredentials>
    </behavior>
  </endpointBehaviors>
 </behaviors>

Если вам нужна дополнительная информация, просто дайте мне знать, и я опубликую полную рабочую конфигурацию клиента.

Изменить извините за задержку

Вы также должны добавить noCheck в конфигурацию сервера:

<behavior name="X509SecureBehavior">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
          <serviceCredentials>
            <serviceCertificate storeName="My" storeLocation="CurrentUser" x509FindType="FindByThumbprint" findValue="aaaa" />
            <clientCertificate>
              <authentication certificateValidationMode="None" revocationMode="NoCheck" />
            </clientCertificate>
          </serviceCredentials>
        </behavior>

Также я не включил ссылку сертификата в определение конечной точки.