Настраиваем в IIS авторизацию по клиентским сертификатам при помощи OpenSSL


    Доброго времени суток, %username%!
    Ранее я рассказывал о генерации сертификатов с эллиптическими кривыми.
    Сегодня я расскажу о том как можно без особых усилий настроить в IIS авторизацию по обычным RSAшным клиентским сертификатам, сгенерировать сертификаты для сервера и клиента. И поможет мне в этом как всегда OpenSSL.
    Для того чтобы все работало нам понадобятся минимум 3 сертификата:
    1. Корневой сертификат (Certificate Authority или CA). Им будем подписывать все остальные.
    2. Сертификат домена (сервера). Им IIS будет проверять клиентов. И наоборот, клиенты смогут проверить подлинность сервера.
    3. Сертификат(ы) клиента(ов)

    image


    Для работы нам понадобится отдельная папка, например c:\iis. В ней необходимо создать файл без расширения serial и записать туда 01, так же там нужно создать пустой файл index.txt. В зависимости от конфигурации OpenSSL может попросить создать внутри этой папки еще какие нибудь. В моем случае это была папка newcerts. Так же в OpenSSL.cfg нужно будет поменять в [ CA_default ] dir на c:/iis

    1) Создадим корневой self-signed сертификат:
    openssl req -new -x509 -newkey rsa:2048 -days 1000 -out c:\iis\ca.crt -keyout c:\iis\ca.key
    • -new означает что мы хотим создать новый запрос
    • -x509 что сразу хотим самоподписанный сертификат
    • -newkey rsa:2048 Пусть тут же и ключик нам сгенерирует длиной 2048 бит. вместо rsa:<кол-во бит>, кстати, можно указывать dsa:<файл с параметрами> или ec:<файл с параметрами>
    • -days 1000 — сертификат истечет через 1000 дней
    • -out и -keyout указывают куда сохранить сертификат и закрытый ключ от него

    После серии несложных вопросов в папке iis появятся сертификат ca.crt и закрытый ключ от него ca.key

    Теперь, чтобы IIS узнавал все сертификаты, подписанные корневым, нужно установить корневой сертификат в хранилище доверенных центров сертификатов компьютера:
    1. Запускаем mmc
    2. Добавляем оснастку сертификаты и указываем, что она будет управлять сертификатами для учетной записи компьютера, иначе ничего не заведется.
    3. Открываем «Доверенные корневые центры сертификации» и импортируем туда наш CA:

    image

    Готово! Можно приступать к работе с сервером.

    2) В консоли управления IIS нужно зайти в «Сертификаты сервера», вызвать меню по правой кнопке и нажать создать новый запрос сертификата. Сохраните его в c:\iis как server.csr

    Теперь подпишем запрос сертификата сервера корневым сертификатом:
    openssl ca -days 1000 -policy policy_anything -keyfile c:\iis\ca.key -cert c:\iis\ca.crt -in c:\iis\server.csr -out c:\iis\server.cer
    -policy policy_anything означает, что сертификату будут предоставлены все возможные политики применения. Самый простой вариант. Остальные параметры, полагаю, в пояснении не нуждаются. Главное, не запутаться где какой файл указывать.
    После этого у нас в c:\iis появится сертификат сервера server.cer, которы нужно установить в IIS.
    Для этого мы опять идем в «сертификаты сервера», выбираем «Запрос установки сертификата» и там указываем c:\iis\server.cer.
    Всё, сертификат у сервера есть.
    Теперь нужно в привязках для узла создать новую https привязку и выбрать из списка наш серверный сертификат:
    image

    После этого нужно в настройках SSL для узла выставить опции следующим образом:image

    Готово! Остался клиент. Но и на этом этапе уже можно зайти на https://localhost/ и увидеть, что без сертификата вас не пускает.

    3) Генерируем запрос для клиентского сертификата
    openssl req -new -newkey rsa:2048 -days 1000 -keyout c:\iis\client.key -out c:\iis\client.csr
    Здесь мы не указывали -x509, поэтому получили обычный запрос на сертификат и закрытый ключ клиента.

    Подписываем запрос:
    openssl ca -days 1000 -policy policy_anything -keyfile c:\iis\ca.key -cert c:\iis\ca.crt -in c:\iis\client.csr -out c:\iis\client.crt
    Тут тоже все понятно, в результате мы получим сертификат слиента client.crt

    Теперь чтобы импортировать сертификат клиента в хранилище сертификатов Windows вместе с ключом, нам необходимо конвертнуть crt+key в контейнер .pfx:
    openssl pkcs12 -export -inkey c:\iis\client.key -in c:\iis\client.crt -out c:\iis\client.pfx
    Ура! Получили client.pfx, дважды кликнув на котором можно вызвать диалог импорта сертификатов и, собственно установить то что получилось в личное хранилище.

    Если все сделано правильно, то после импорта сертификата в личное хранилище вас должно пустить по адресу https://localhost/ и показать содержимое.

    Можно сгенерировать еще один сертификат с другими данными и тоже его импортировать. Тогда при заходе на сервер вам предложат выбрать любой из них:image

    Вот и все )
    На последок код aspx странички (сохраните его как Default.aspx), который позволит вам всё проверить: Он выводит информацию о клиентском сертификате:
    <%@ Page Language="C#"%>
    <%@ Import Namespace="System.Security.Cryptography" %>
    <script runat="server">
    private void Page_Load(object sender, System.EventArgs e)
    {
        Response.Write("<table width=50% cellspacing=1><tr> <th colspan=2>Current ClientCertificate Settings</th></tr>");
        
        Response.Write("<tr><td>Subject</td><td>"+Request.ClientCertificate.Subject+"</td></tr>");
        Response.Write("<tr><td>SHA1 Fingerprint</td><td>"+GetCertificateFingerPrint()+"</td></tr>");
        Response.Write("<tr><td>Valid from</td><td>"+Request.ClientCertificate.ValidFrom+"</td></tr>");
        Response.Write("<tr><td>Valid Until</td><td>"+Request.ClientCertificate.ValidUntil+"</td></tr>");
        Response.Write("<tr><td>Issuer</td><td>"+Request.ClientCertificate.Issuer+"</td></tr></table>");
    }
    private String GetCertificateFingerPrint()
            {
                if (Request.ClientCertificate.IsPresent)
                {
                    byte[] raw = Request.ClientCertificate.Certificate;
                    SHA1 sha1 = new SHA1CryptoServiceProvider();
                    byte[] hash = sha1.ComputeHash(raw);
                    StringBuilder res = new StringBuilder();
                    for (int i = 0; i < hash.Length; i++)
                    {
                        res.Append(hash[i].ToString("X2"));
                    }
                    return res.ToString();
                }
                return "";
            }
    </script>



    Have fun!

    Поделиться публикацией

    Комментарии 12

      0
      замечательно и позновательно :)

      кстати, а крайний IIS умеет быть fcgi бакендом? :)
        +1
        Спасибо за хорошую статью.

        В дополнение к статьи несколько полезных команд:
        inetmgr — оснастка iss
        certmgr.msc — оснастка сертификаты
          0
          учтем ) как раз вспоминал что то подобное перед написанием
          0
          Спасибо за статью. Задумался о применении подобной аутентификации на одном из проектов :)

          Хотел задать вопрос о кросс-платформенности/кросс-браузерности, но нашёл аналогичную статью для Apache / Firefox+Safari.
            +1
            Такое ощущение, что схожие задачи возникают у многих людей одновременно. Буквально пару недель назад проделывал те же самые шаги, что описаны в статье, только «обложившись мануалами»
              0
              А можно ли как-то переопределить окно выбора сертификата?

              Нужна примерно такая логика работы:
              1) Пользователь переходит на страницу где отображаются все установленные в системе сертификаты.
              2) Пользователь выбирает подходящий сертификат и пробует войти с ним.
              3) Если серт правильный то пользователю прописываются куки и он дальше работает с системой.

              Примерно такая логика реализована в системе сдачи налоговой отчетности Контур-Экстерн.

              image
                0
                Работает ли маппинг many-to-one в IIS с сертификатами, созданными в openssl?
                У меня не работает (IIS 7.5). Работает почему-то только с теми, что созданы makecert… или one-to-one (где указывается Base64 сертификата).
                  0
                  Статья 2011 года, вряд ли вам ответят )
                    0
                    дык, я автору (т.е. Вам) и задавал :)
                    * к слову, у 73 в избранном )
                      0
                      Я с IIS завязал очень давно, сори )
                        0
                        похоже, это трабла IIS 7.5. В IIS 10 всё работает как задумано.

                        JFI
                  +1
                  Ваша статья лучшая на эту тему, что я нашёл.
                  Так как при настройке я столкнулся с проблемами, напишу тут, что помогло их решить:

                  1) пара советов отсюда:
                  switch-case.ru/59638860
                  — Удалить несамоподписанные сертификаты из списка корневых доверенных
                  Найти их можно такой командой Powershell:
                  Get-Childitem cert:\LocalMachine\root -Recurse |
                  Where-Object {$_.Issuer -ne $_.Subject}

                  — Почистить список доверенных корневых сертификатов или отключить листинг
                  Set HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL Value name: SendTrustedIssuerList Value type: REG_DWORD Value data: 0

                  ещё странно:
                  вроде после этого заработало, но потом опять вылезали проблемы.
                  я полез включать трассировку, установил ASP и CGI и модуль трассировки — и проблемы ушли целиком.
                  Трассировать не пришлось ничего :(

                  Инструкция по настройке трассировки, которая может помочь, если проблемы останутся (в логе будет писаться, почему не принят клиентский сертификат):
                  docs.microsoft.com/en-us/iis/troubleshoot/using-failed-request-tracing/troubleshooting-failed-requests-using-tracing-in-iis

                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                  Самое читаемое