(MVC) MVC (2011 год)

Организация SSL транспортного уровня по программно загружаемому клиентскому сертификату.

Мне довольно часто приходится заниматься организацией защищенных соединений:


В принципе, защиту трафика можно организовать на различных уровнях:


Протоколы защиты бывают разные:


Теперь, когда я обьяснил что такое сертификат, как он используется для установления SSL-соединения - посмотрим куда его можно поставить - на сервер или на клиент:


Итак, на этой страничке я покажу, как работать с клиентскими сертификатами, но не просто для реквестов на web-сервер, как в моей софтине Электронная Москва в вашей квартире, а для SSL-реквестов к SOAP-WSDL сервису (который не имеет отображаемой в браузере странички). Причем в описании будет присутствовать одна особенность - клиентский сертификат будет не просто загружен в IIS, а будет искаться в хранилище сертификатов моим собственным кодом и загружаться для формирования SOAP-реквестов программно.

Если вы о хотите почитать о SOAP-WSDL сервисах вообще, то можете почитать следующие мои странички:


В виндузне существуют остнастка управления сертификатами - она раскрывает 13 узлов различного назначения из защищенного хранилища, в котором хранятся сертификаты. Этих 13-ти узловых защищенных хранилищ существует два - в контексте текущего пользователя и текущей машины. На скринах ниже видно, как после введения в командной строке MMC (Менеджера управления остнастками) - можно запустить оснастку управления сертифкатами либо по контексту кампутера (LocalMachine) либо по контексту пользователя (CurrentUser):



Кроме того, для загрузки сертификатов в IIS7 нужна специальная оснастка ClientCertificateMapping - она отсутствует в изначальной комплектации IIS.

Кроме того, для преобразования различных форматов сертифкатов друг в друга, генерации ключей и всех прочих операций с сертификатами и ключами вам потребуется установить OpenSSL:



Итак, начинаем операции по организации SSL-шифрования на основе клиентского сертификата начинается с генерации личного секретного ключа:

  • Создаем пару секретный ключ и публичный ключ:

  • И отправляем CSR-файл с публичным ключом на подписание на сервер. Там удостоверяют наш публичный ключ своим публичным ключом, записывают в какую-то свою базу на сервере - имя клиента, чтобы когда WEB-сервер поднимет с транспортного уровня Request.ServerVariables("HTTP_CERTIFICATE_NUMBER") и Request.ServerVariables("HTTP_SUBJECT") - можно было понять что именно за клиент обратился по SSL на сервер. И создают собственно сертификат в формате CRT - это уже сертификат, который содержит и наш открытый клиентский ключ и подпись сервера, которым заверен наш ключ. Весь этот процесс называется Enrolment сертификата.

  • Теперь нужно собрать пакет PFX, который будет содержать и наш секретный ключ, и наш открытый ключ, подписанный сервером.

  • Теперь этот PFX-сертификат надо установить. Этот сертификат содержит уже не только открыто распространяемую информацию (наш личный открытый ключ, заверенный сервером), но и наш личный секретный ключ, применяемый для расшифровки ответов. Предпочтительно выбирать защищенное Windows-хранилище My.

  • Теперь надо обеспечить, чтобы учетная запись (под которой выполняется узел IIS) - имела право доступа к этому сертификату. Тут есть тысяча способов. Сейчас мне некогда возиться, я просто зашел на один из своих web-сервером и поставил что этот узел выполняется с правами администратора.

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

    Я отработал себе вот такой шаблон кода для SSL-обращения к защищенному SOAP-WSDL сервису:

    • Я создаю webApplication - чтобы сразу же защищенный по SSL-сервис можно было удобно добавлять в ссылки:

    • Далее ставлю ссылку на защищенный сервис:

    • Теперь, когда студия создала прокси-классы по WSDL, который предоставил защищенный SOAP-сервис - в студии появляются подсказки на каждый метод сервера (и его параметры).

    • Сделав небольшие свои собственные врапперы вокруг классов, сформированных студией по WSDL - я уже могу делать собственно код. В данном случае, как вы видите - я использую PostgreSQL (через провайдер npgsql):

    • Номер созданного ранее и установленного в защищенное хранилище My моего SSL-сертификата в формате PFX (содержащего закрытый ключ и открытый ключ, подписанный открытым ключом сервера) - я указывают в конфиге:



    • Теперь я покажу, как я добавил поиск сертификата в хранилище и добавил его к защищенному по SSL-обращению:

      Фрагмент кода, который вы видите на рисунке - выглядит вот так:

         1:  Public Class Gate
         2:   
         3:      Dim ShopService1 As ru.inplat.merchant_remote.ShopService
         4:   
         5:      Public Sub New()
         6:          ShopService1 = New ru.inplat.merchant_remote.ShopService
         7:          Dim ShopServiceCert As System.Security.Cryptography.X509Certificates.X509Certificate2
         8:          Dim CertStore As System.Security.Cryptography.X509Certificates.X509Store = New System.Security.Cryptography.X509Certificates.X509Store
         9:          CertStore.Open(System.Security.Cryptography.X509Certificates.OpenFlags.MaxAllowed)
        10:          For Each OneCert As System.Security.Cryptography.X509Certificates.X509Certificate2 In CertStore.Certificates
        11:              If OneCert.SerialNumber = System.Configuration.ConfigurationManager.AppSettings("CertNumber") Then
        12:                  ShopServiceCert = OneCert
        13:                  GoTo OK1
        14:              End If
        15:          Next
        16:          Throw New Exception("No certificate " & System.Configuration.ConfigurationManager.AppSettings("CertNumber"))
        17:  OK1:    ShopService1.ClientCertificates.Add(ShopServiceCert)
        18:      End Sub
        19:   
        20:  ...

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

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



      <00>  <01>  <02>  <03>  <04>  <05>  <06>  <07>  <08>  <09>  <10>  <11>  <12>  <13>  <14>  <15>  <16>  <17>  <18>  <19>  <20>  <21
      <SITEMAP>  <MVC>  <ASP>  <NET>  <DATA>  <KIOSK>  <FLEX>  <SQL>  <NOTES>  <LINUX>  <MONO>  <FREEWARE>  <DOCS>  <ENG>  <CHAT ME>  <ABOUT ME>  < THANKS ME>
      g2019507">