Аутентификация запроса WCF через сертификат клиента по HTTPS - PullRequest
9 голосов
/ 04 декабря 2010

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

Проще говоря, я хочу, чтобы служба WCF требовала сертификат клиента (который сервер будет иметь в своем хранилище сертификатов), а затем осуществляла доступ к этой идентификации с помощью System.ServiceModel.ServiceSecurityContext.Кроме того, для этого необходимо использовать безопасность транспорта.

Вот мой конфиг сервера:

<system.serviceModel>
    <services>
      <service behaviorConfiguration="requireCertificate" name="Server.CXPClient">
        <endpoint address="" binding="wsHttpBinding" bindingConfiguration="wsHttpEndpointBinding" name="wsHttpEndpoint" contract="PartnerComm.ContentXpert.Server.ICXPClient" />
        <endpoint address="mex" binding="wsHttpBinding" bindingConfiguration="wsHttpEndpointBinding" name="mexEndpoint" contract="IMetadataExchange" />
        <host>
          <baseAddresses>
            <add baseAddress="https://localhost:8371/Design_Time_Addresses/Server/CXPClient/" />
          </baseAddresses>
        </host>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="requireCertificate">
          <serviceMetadata httpsGetEnabled="true" />
          <serviceCredentials>
            <serviceCertificate findValue="CyberdyneIndustries" storeLocation="LocalMachine" storeName="TrustedPeople" x509FindType="FindBySubjectName"/>
            <clientCertificate>
              <authentication certificateValidationMode="ChainTrust" trustedStoreLocation="LocalMachine" />
            </clientCertificate>
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <bindings>
      <wsHttpBinding>
        <binding name="wsHttpEndpointBinding" maxBufferPoolSize="5242880" maxReceivedMessageSize="5242880">
          <readerQuotas maxDepth="32" maxStringContentLength="5242880" maxArrayLength="1073741824" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
          <security mode="Transport">
            <transport clientCredentialType="Certificate" />
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
  </system.serviceModel>

Вот мой конфиг клиента:

  <system.serviceModel>
    <bindings>
      <wsHttpBinding>
        <binding name="wsHttpEndpoint" closeTimeout="00:01:00" openTimeout="00:01:00"
          receiveTimeout="00:10:00" sendTimeout="00:01:00" bypassProxyOnLocal="false"
          transactionFlow="false" hostNameComparisonMode="StrongWildcard"
          maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text"
          textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false">
          <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
            maxBytesPerRead="4096" maxNameTableCharCount="16384" />
          <reliableSession ordered="true" inactivityTimeout="00:10:00"
            enabled="false" />
          <security mode="Transport">
            <transport clientCredentialType="Certificate" />
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
    <client>
      <endpoint address="https://localhost:8371/Design_Time_Addresses/Server/CXPClient/"
        binding="wsHttpBinding" bindingConfiguration="wsHttpEndpoint" behaviorConfiguration="ClientCertificateBehavior"
        contract="ContentXPertServer.ICXPClient" name="wsHttpEndpoint" />
    </client>
    <behaviors>
      <endpointBehaviors>
        <behavior name="ClientCertificateBehavior">
          <clientCredentials>
            <clientCertificate x509FindType="FindBySubjectName" findValue="CyberdyneIndustries" storeLocation="LocalMachine" storeName="TrustedPeople" />
          </clientCredentials>
        </behavior>
      </endpointBehaviors>
    </behaviors>
  </system.serviceModel>

Код все прекрасно работает, когда безопасностьmode = 'None' по http, но, конечно же, в System.ServiceModel.ServiceSecurityContext нет аутентификации и ничего нет.Я испробовал десятки вариантов всех этих элементов, и все это неизбежно заканчивается запросом, генерирующим исключение «Существующее соединение было принудительно закрыто удаленным хостом».

Я использую самоподписанный сертификат "CyberdyneIndustries", сертификат которого я добавил в хранилище доверенных сертификатов.Сертификат проверяется, когда я его просматриваю.Я прошел через адское управление пространством имен http и также решил эти проблемы.Похоже, что WCF действительно не поддерживает это ... пожалуйста, скажите мне, что я не прав.

TIA.

Ответы [ 4 ]

2 голосов
/ 07 декабря 2010

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

Однако реализация защиты сообщений выявила ОГРОМНУЮ проблему, и это могло быть причиной проблемы безопасности транспорта.В MSDN есть фрагмент ядовитой документации:

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

На этой странице команда для создания самоподписанного сертификата выглядит следующим образом:

makecert -sk MyKeyName -iv RootCaClientTest.pvk -n "CN = tempClientcert" -ic RootCaClientTest.cer -sr currentuser -ss my -sky signature -pe

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

1 голос
/ 04 ноября 2014

Я знаю, что это 3 года, но для тех, кто все еще может быть заинтересован ...

Я нахожусь в процессе изучения WCF (безопасность среди прочего) и смог заставить работать вещиправильно с netTcpBinding (предположительно, это будет работать и для WsHttpBindings) с использованием режима безопасности транспорта с clientCredentialType = "Certificate" (и, protectionLevel = "EncryptAndSign", хотя это не было проблемой).

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

Вот мой конфиг на стороне сервера:

<configuration>
  <system.serviceModel>
    <services>
      <service name="MyNamespace.MyService" behaviorConfiguration="MyServiceBehavior">
        <endpoint address="net.tcp://localhost:9002/MyServer" binding="netTcpBinding" bindingConfiguration="TcpCertSecurity" contract="MyNamespace.IMyService" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="MyServiceBehavior">
          <serviceCredentials>
            <serviceCertificate findValue="MyServiceCert" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
            <clientCertificate>
              <authentication certificateValidationMode="PeerTrust"/>
            </clientCertificate>
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <bindings>
      <netTcpBinding>
        <binding name="TcpCertSecurity">
          <security mode="Transport">
            <transport clientCredentialType="Certificate" protectionLevel="EncryptAndSign" />
          </security>
        </binding>
      </netTcpBinding>
    </bindings>
  </system.serviceModel>
</configuration>

И моя конфигурация на стороне клиента:

<configuration>
  <system.serviceModel>
    <client>
      <endpoint address="net.tcp://localhost:9002/MyServer" binding="netTcpBinding"
          bindingConfiguration="TcpCertSecurity" contract="MyNamespace.IMyService"
          behaviorConfiguration="MyServiceBehavior">
        <identity>
          <dns value="MyServiceCert" />
        </identity>
      </endpoint>
    </client>
    <bindings>
      <netTcpBinding>
        <binding name="TcpCertSecurity">
          <security mode="Transport">
            <transport clientCredentialType="Certificate" protectionLevel="EncryptAndSign" />
          </security>
        </binding>
      </netTcpBinding>
    </bindings>
    <behaviors>
      <endpointBehaviors>
        <behavior name="MyServiceBehavior">
          <clientCredentials>
            <serviceCertificate>
              <authentication certificateValidationMode="PeerTrust" />
            </serviceCertificate>
            <clientCertificate findValue="MyServiceCert" storeLocation="LocalMachine" storeName="TrustedPeople" x509FindType="FindBySubjectName" />
          </clientCredentials>
        </behavior>
      </endpointBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>

Я создал цепочку сертификатов длясервера (самозаверяющий сертификат доверенного корня + сертификат, созданный с использованием этого корня), используя методику, описанную здесь , и хранит как корневой сертификат, так и дочерний сертификат в хранилище сертификатов моего хост-компьютера.И, наконец, я импортировал этот сертификат сервера + открытый ключ в хранилище сертификатов на моем хост-компьютере клиента (в LocalMachine / TrustedPeople).

1 голос
/ 07 декабря 2010

Успешно ли происходит SSL-рукопожатие?Включите ведение журнала SChannel для устранения неполадок уровня SSL.См. Эту старую статью базы знаний: Как включить ведение журнала событий Schannel в IIS .Несмотря на то, что это КБ для W2K и XP, шаги по включению ведения журнала SChannel одинаковы и остаются действительными в более новых системах.Включив ведение журнала, вы сможете определить, почему SSL отклоняет сертификат.

0 голосов
/ 07 декабря 2010

WsHttpBinding поддерживает аутентификацию сертификата для обеспечения безопасности транспорта.

Там может быть несколько вещей неправильно:

  1. Вы добавили оба сертификата в свой магазин? CyberdyneIndustries, а также CA, который вы использовали, чтобы подписать его? CA должен быть в «доверенных корневых центрах сертификации»

  2. Кроме того, я сделал это самостоятельно, никогда на сервере Visual Studio Dev. Попробуйте разместить свой сервис в IIS хотя бы. Я не уверен, поддерживает ли сервер VS Dev сертификаты.

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

    <behavior name="ClientCertificateBehavior">
    <clientCredentials>
        <clientCertificate x509FindType="FindBySubjectName" findValue="CyberdyneIndustries" storeLocation="LocalMachine" storeName="TrustedPeople" />
        <serviceCertificate>
            <authentication certificateValidationMode="None"/>
        </serviceCertificate>
    </clientCredentials>
    

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...