Отключить сертификат клиента SSL на* некоторых * контроллерах WebAPI?

редактировать для будущих читателей: к сожалению, награда присуждена ответ ничего не получается, я ничего не могу с этим поделать. Но прочитай мой собственный ответ. ниже (через тестирование) - подтверждена работа с минимальными изменениями кода

У нас есть облачная служба Azure (WebRole), которая полностью находится в ASP.NET WebAPI 2.2 (нет MVC, передний конец угловой). Некоторые из наших контроллеров / конечных точек REST разговаривают с сторонним облачным сервисом через SSL (клиентский сертификат auth / mutual auth), а остальные контроллеры/конечные точки общаются с интерфейсом HTML5/AngularJS, также через SSL (но более традиционный сервер auth SSL). У нас нет конечной точки без SSL. Мы включили клиентский SSL через задачу запуска облачного сервиса, например:

IF NOT DEFINED APPCMD SET APPCMD=%SystemRoot%system32inetsrvAppCmd.exe
%APPCMD% unlock config /section:system.webServer/security/access

проблема: этот параметр является общесайтовым, поэтому даже когда пользователи попадают на первую страницу (скажем https://domain.com, возвращает индекс.html для angularJS) их браузер запрашивает у них сертификат SSL клиента. (изображение ниже)

Если есть способ, чтобы либо

  1. ограничить запросы SSL-сертификата клиента только контроллерами WebAPI, которые обращаются к сторонней облачной службе?

или

  1. пропустить SSL-аутентификацию клиента для наших интерфейсных контроллеров webapi?

веб-сервера.config является сложным, но соответствующий фрагмент ниже:

<system.webServer>
  <security>
    <access sslFlags="SslNegotiateCert" />
  </security>
</system.webServer>

и скриншот клиента, попавшего в обычный Конечная точка WebAPI еще пытается аутентификацию SSL клиента (происходит в любом браузере, Chrome, Firefox или IE) enter image description here

3 ответов


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

решение основано на web.config это вызывает специальную обработку "каталогов" (работает и для виртуальных папок или маршрутов WebAPI).

вот желаемая логика:

https://www.server.com/acmeapi/** => SSL с клиентскими сертификатами

https://www.server.com/** => SSL

вот соответствующая конфигурация

<configuration>
  ...
  <system.webServer>
    <!-- This is for the rest of the site -->
    <security>
      <access sslFlags="Ssl" />
    </security>
  </system.webServer>

  <!--This is for the 3rd party API endpoint-->
  <location path="acmeapi">
    <system.webServer>
      <security>
        <access sslFlags="SslNegotiateCert"/>
      </security>
    </system.webServer>
  </location>
...
</configuration>

бонусные баллы

вышеуказанное настроит рукопожатие SSL соответственно. Теперь вам все равно нужно проверить сертификат SSL клиента в вашем коде, если это тот, который вы ожидаете. Это делается следующим образом


вы можете просто разрешить простой http-трафик в интернете.настройте уровень и напишите пользовательский обработчик делегирования в конвейере Web Api для этого. Вы можете найти клиентский сертификат, делегирующий обработчик здесь и здесь. Затем вы можете сделать этот обработчик активным "по маршруту", как в этом примере здесь:

вот как будет выглядеть ваша конфигурация маршрута.

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.Routes.MapHttpRoute(
            name: "Route1",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

        config.Routes.MapHttpRoute(
            name: "Route2",
            routeTemplate: "api2/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional },
            constraints: null,
            handler: new CustomCertificateMessageHandler()  // per-route message handler
        );

        config.MessageHandlers.Add(new SomeOtherMessageHandler());  // global message handler
    }
}

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


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

Итак, вот ваши варианты:

  1. разверните вторую веб-роль, настроенную на не согласование клиентских сертификатов. Для этого вам понадобится второй домен, так как это, по сути, отдельная служба. Так что у тебя есть https://domain.com указывая на не-клиент-свиду один и https://foo.domain.com указывая на один, что требует клиент сертификаты.

  2. используйте ту же веб-роль, но настройте второй порт для прослушивания IIS и настройте его так, чтобы он не согласовывал сертификат клиента. Использование нестандартных портов-это боль, хотя, так как один из ваших клиентов должен будет сделать https://domain.com:444 (или какой-либо другой порт, кроме 443).

  3. отключить согласование сертификата клиента по всем направлениям. Это может не работать в зависимости от службы к клиенту сертификат, но обычно при доступе к свойству ClientCertificate в системе.Сеть.Объект HttpRequest (или эквивалент), он будет согласовывать сертификат по требованию. Это означает, что он прозрачно разрывает существующий сеанс SSL и настраивает новый, на этот раз бросая вызов клиенту для сертификата. Это довольно неэффективно, так как настройка SSL-соединения в первую очередь занимает несколько поездок туда и обратно, и делать это дважды больно. Но, в зависимости от имеющихся вариантов требования к производительности для запросов, использующих клиентские сертификаты, и если вы получите много повторного использования соединения из keep-alives, этот параметр может иметь смысл.

надеюсь, что это помогает.