Реализация проверки подлинности сертификата в ASP.NET Core 3.1

Я создаю небольшую функцию проверки подлинности сертификата ASP.NET Core, как указано в официальные документы.

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

На изображении ниже показано, что я могу защитить метод Index action, для которого теперь требуется сертификат клиента. Другой метод действия, который называется «Конфиденциальность», не требует сертификата клиента. В результате действие Index открывается в браузере (получается ошибка 403), но действие Privacy открывается в браузере.

введите описание изображения здесь

Полные коды

<сильный>1. Program.cs

public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
    .ConfigureWebHostDefaults(webBuilder =>
    {
        webBuilder.UseStartup<Startup>();
        webBuilder.ConfigureKestrel(o =>
        {
            o.ConfigureHttpsDefaults(o =>
                o.ClientCertificateMode =
                    ClientCertificateMode.RequireCertificate);
        });
    });

<сильный>2. Startup.cs

public Startup(IConfiguration configuration)
{
    Configuration = configuration;
}

public IConfiguration Configuration { get; }

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();
    services.AddAuthentication(
        CertificateAuthenticationDefaults.AuthenticationScheme)
        .AddCertificate(options =>
        {
            options.Events = new CertificateAuthenticationEvents
            {
                OnCertificateValidated = context =>
                {
                    var validationService = context.HttpContext.RequestServices.GetService<MyCertificateValidationService>();

                    if (validationService.ValidateCertificate(context.ClientCertificate))
                    {
                        context.Success();
                    }
                    else
                    {
                        context.Fail("invalid cert");
                    }

                    return Task.CompletedTask;
                },
                OnAuthenticationFailed = context =>
                {
                    context.Fail("invalid cert");
                    return Task.CompletedTask;
                }
            };
        });
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseCertificateForwarding();
    app.UseAuthentication();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
    });
}

<сильный>3. MyCertificateValidationService.cs

public class MyCertificateValidationService
{
    public bool ValidateCertificate(X509Certificate2 clientCertificate)
    {
        var cert = new X509Certificate2(Path.Combine("localhost_root_l1.pfx"), "1234");
        if (clientCertificate.Thumbprint == cert.Thumbprint)
        {
            return true;
        }

        return false;
    }
}

<сильный>4. Защищенные и незащищенные методы действий

[Authorize]
public IActionResult Index()
{
    return View();
}

public IActionResult Privacy()
{
    return View();
}

Примечание. Метод действия Index требует аутентификации клиента, в то время как Privacy не требует сертификата клиента.

Проблемы. Проблемы, с которыми я сталкиваюсь:

  1. CertificateAuthenticationEvents и OnAuthenticationFailed расположены в ConfigureServices() методе файла startup.cs, который я не вызывал. Я проверил их, поставив точки останова, но точка останова не достигнута.

  2. Метод MyCertificateValidationService.cs класса ValidateCertificate() также не вызывается. Я также проверил это с помощью точки останова

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

Обновить

Я создал 2 сертификата на С# как объяснено в этом руководстве. Эти:

  1. Корневой сертификат с именем root_localhost.pfx
  2. Сертификат клиента с именем client.pfx

Я сделал 2 вещи с этими сертификатами:

а. Я добавил root_localhost.pfx в доверенные корневые центры сертификации (в Windows) для локального компьютера (с помощью CertManager).

б. Я импортировал сертификат клиента в браузере Chrome.

Затем я выбрал проект в VS 2019 (консоль) вместо «IIS Express» и запустил свой проект. Я открыл URL-адрес веб-сайта в окне инкогнито, URL-адрес - https://localhost:5001

Chrome предлагает выбрать сертификат, см. изображение ниже: введите здесь описание изображения

При выборе этого я получаю Этот сайт недоступен - ERR_SPDY_INADEQUATE_TRANSPORT_SECURITY, см. изображение ниже:

введите описание изображения здесь

Почему это происходит????


person yogihosting    schedule 01.03.2020    source источник
comment
Вы настроили свой браузер для использования сертификата клиента?   -  person Sergey L    schedule 01.03.2020


Ответы (5)


На данный момент ваше приложение не настроено на использование клиентских сертификатов. Причина в том, что вы запускаете (размещаете) свое приложение в IIS Express. Есть 2 варианта:

1) Самый простой, переключиться на запуск в режиме Project (приложение будет запускаться в окне консоли). Вы также можете запустить его вручную в консоли.

2) Чуть более сложный метод — настроить IIS Express для работы с клиентскими сертификатами. Выполните следующие шаги: 2.1) отредактируйте файл \config\applicationhost.config и измените раздел ниже (изменения - Запретить на Разрешить).

      <sectionGroup name="security">
        <section name="access" overrideModeDefault="**Allow**" />
        <section name="applicationDependencies" overrideModeDefault="Deny" />
        <sectionGroup name="authentication">
          <section name="anonymousAuthentication" overrideModeDefault="**Allow**" />

2.2) в вашем проекте добавьте следующий файл web.config

<configuration>
    <system.webServer>
        <security>
            <access sslFlags="Ssl,SslNegotiateCert,SslRequireCert" />
          <authentication>
            <anonymousAuthentication enabled="true" />
          </authentication>
        </security>
    </system.webServer>
</configuration>

Следующий:

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

#create key
openssl req -newkey rsa:4096 -keyout key.pem -out csr.pem -nodes -days 365 -subj "/CN=Your name"
#create certificate
openssl x509 -req -in csr.pem -signkey key.pem -out cert.pem -days 365
#self sign it
openssl pkcs12 -export -in cert.pem -inkey key.pem -out your_cert.p12

Поскольку этот сертификат является самоподписанным, его необходимо добавить в доверенные корневые центры сертификации (в Windows) для локального компьютера (с помощью CertManager).

После этого вам необходимо установить его (импортировать) в ваше Хранилище Персональных Сертификатов, используя тот же CertManager, но только для текущего пользователя. Альтернативный метод — использовать настройки Chrome («Управление сертификатами»). Это необходимо для того, чтобы Chrome мог отправить сертификат на сервер.

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

            services.AddAuthentication(
                    CertificateAuthenticationDefaults.AuthenticationScheme)
                    .AddCertificate(options => 
                    { 
                        **options.AllowedCertificateTypes = CertificateTypes.All**;

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

Совет. Возможно, вам не будет предложено выбрать, какой сертификат использовать, если вы снова посещаете ту же страницу, пока вы не закроете все экземпляры Chrome. если вы хотите, чтобы он попросил выбрать, какой сертификат использовать, откройте новое окно в режиме инкогнито.

person Sergey L    schedule 01.03.2020
comment
Когда я переключаю режим проекта в VS 2019, я получаю сообщение «Этот сайт недоступен» и «ERR_SPDY_INADEQUATE_TRANSPORT_SECURITY». Пожалуйста, предложите? - person yogihosting; 02.03.2020
comment
Какой URL вы используете для доступа к сайту? Для режима проекта это обычно localhost:5001 или аналогичный. Если вы не добавляете сертификат локального сервера или другой сертификат, который вы используете, в доверенный корень, вы должны разрешить переход на этот сайт. Нажмите на расширенную ссылку под предупреждением. Любые скриншоты также могут помочь понять вашу проблему. - person Sergey L; 02.03.2020
comment
URL-адрес: localhost:5001. Я объясняю, сначала я создал 2 сертификата, которые являются корневым сертификатом и сертификатом клиента на C# (используя этот учебник damienbod.com/2019/06/27/). Затем я добавил корневой сертификат в «Доверенные корневые центры сертификации» из CertManager, как вы сказали. Я также импортировал «Сертификат клиента» в браузер Chrome, как вы сказали. Я получаю сообщение об ошибке - "ERR_SPDY_INADEQUATE_TRANSPORT_SECURITY". Что не так, спасибо? - person yogihosting; 02.03.2020
comment
Проблема может заключаться в том, как вы создали эти сертификаты. давайте сделаем это по шагам. 1) удалите корневой сертификат из проекта, если вы его использовали. Запустите проект с сертификатом localhost, созданным VS. он должен спросить, хотите ли вы добавить корневой сертификат, вы можете согласиться. 2) Если все в порядке, и вы заходите на свой сайт, он должен либо попросить вас выбрать сертификат клиента, либо вернуть ошибку (403) - person Sergey L; 02.03.2020
comment
3) Если у вас все хорошо, создайте самозаверяющий сертификат клиента, как я описал, добавьте его в хранилище chrome и корневого сертификата, как описано. Получите доступ к сайту, выберите этот добавленный сертификат, вы сможете получить доступ к сайту. Если что-то работает не так, как описано, зарегистрируйте ошибки и не переходите к следующему шагу. если вам удалось пройти шаг № 3, это будет означать, что он работает с простым сертификатом, вы можете начать создавать более сложные сертификаты. - person Sergey L; 02.03.2020
comment
Я полагаю, что эта проблема может быть связана с тем, как вы создаете сертификат, нажимаете на значок замка и смотрите, какой сертификат вы используете. Кроме того, это может быть связано: «ковбойский веб-сервер, использующий http2 и tls, получает ошибку spdy, неадекватную безопасность транспорта»> stackoverflow.com/questions/53086676/ support.microsoft.com /ru-ru/help/187498/ - person Sergey L; 02.03.2020

Недавно я застрял в той же проблеме и успешно решил ее. Есть две проблемы с тестовым проектом, над которым вы работаете.

  1. Как упоминалось другими разработчиками, режим отзыва следует отключить, используя приведенный ниже фрагмент.
                {
                    options.RevocationMode = X509RevocationMode.NoCheck; 

  1. Зарегистрируйте MyCertificateValidationService в DI (ConfigureServices), используя приведенный ниже фрагмент. services.AddTransient<MyCertificateValidationService>();

Как только вы внесете эти изменения, ваша точка останова должна попасть в MyCertificateValidationService.ValidateCertificate().

    public class MyCertificateValidationService
    {
        public bool ValidateCertificate(X509Certificate2 clientCertificate)
        {
            var cert = new X509Certificate2(Path.Combine("localhost_root_l1.pfx"), "1234");
            if (clientCertificate.Thumbprint == cert.Thumbprint)
            {
                return true;
            }

            return false;
        }
    }
person palcoder    schedule 02.06.2021

options.RevocationMode = X509RevocationMode.NoCheck

настройка это сработало для меня

person Gunni Saggu    schedule 07.04.2020
comment
Куда положить? - person yogihosting; 08.04.2020
comment
перед этой строкой options.Events = new CertificateAuthenticationEvents в startup.cs - person Gunni Saggu; 08.04.2020

Недавно мне тоже пришлось столкнуться с этим, и я задокументировал свои шаги здесь. Они довольно длинные, поэтому я рекомендую ознакомиться с README и следовать инструкциям.

Я все равно выложу тему здесь для тех, кто заинтересован:


Сертификаты

  1. Запустите файл certcrt.cmd и следуйте инструкциям по созданию файлов .cer, .pfx и .crl.
  2. Import client certificate to Current User\Personal. This is usually done during creation.
    1. Windows+R
    2. Введите certmgr.exe, затем введите
    3. Щелкните правой кнопкой мыши Личный
    4. Все задачи › Импорт
    5. Выберите сгенерированный .cer файл клиента
  3. Import server certificate to Local Computer\Trusted Root Certitificates Authorities
    1. Windows+R
    2. Введите certlm.exe, затем Ctrl+Shift+Enter (начать от имени администратора)
    3. Щелкните правой кнопкой мыши Доверенные корневые центры сертификации.
    4. Все задачи › Импорт
    5. Выберите сгенерированный .cer файл
  4. Импортировать список отозванных сертификатов. То же, что и выше, но выберите файл .crl

ИИС/ИИС Экспресс

Запустите файл iis.cmd, чтобы обновить соответствующие разделы конфигурации. Раздел iisClientCertificateMappingAuthentication должен быть включен, а для раздела access sslFlags должно быть установлено значение Ssl, SslNegotiateCert, SslRequireCert`.

Заявление

  1. Добавить пакет Microsoft.AspNetCore.Authentication.Certificate nuget

  2. Настроить протокол аутентификации

    services
         .AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme)
         .AddCertificate(options =>
         {
             options.AllowedCertificateTypes = CertificateTypes.All;
             options.Events = new CertificateAuthenticationEvents
             {
                 OnCertificateValidated = context =>
                 {
                     // Do validation on context.Certificate here
                     return Task.CompletedTask;
                 },
                 OnAuthenticationFailed = context =>
                 {
    
                     return Task.CompletedTask;
                 }
             };
         });
    
  3. Добавьте app.UseAuthentication() перед app.UseAuthorization(), чтобы подключиться к CertificateAuthenticationEvents.OnCertificateValidated. Это никогда не называется иначе, оставляя открытым для любого сертификата.

ВОПРОСЫ

Ошибка HTTP 403.16 — Запрещено. Сертификат вашего клиента либо не является доверенным, либо недействителен.

См. шаг 2 сертификатов.

Предупреждение: проверка сертификата не удалась, тема CN=ancc_client. RevocationStatusUnknown Функция отзыва не смогла проверить отзыв сертификата.

См. шаг 3 сертификатов или отключите проверку восстановления options.RevocationMode = X509RevocationMode.NoCheck

person joacar    schedule 17.09.2020

Ниже приведено единственное, что требовалось, просто чтобы обойти ошибку сертификата при вызове на локальном хосте, подписанном самостоятельно. Обратите внимание, что я конструктор, внедряющий HttpClient (как описано здесь) В классе StartUp,

  public void ConfigureServices(IServiceCollection services)
    {           

        services.AddControllersWithViews();
        services.AddHttpClient().ConfigurePrimaryHttpMessageHandler(() =>
        {
            return new HttpClientHandler()
            {
                ServerCertificateCustomValidationCallback = (request, certificate, certificateChain, policy) => true
            };
        }); 

    }       

Я получил вышеуказанное переопределение проверки из этой статьи: Пользовательская проверка сертификата в .NET .

person Anusha Ganegoda    schedule 11.02.2021