ASP.NET Core 3.1 中的证书身份验证实现

Posted

技术标签:

【中文标题】ASP.NET Core 3.1 中的证书身份验证实现【英文标题】:Certificate Authentication Implementation in ASP.NET Core 3.1 【发布时间】:2020-03-01 17:07:31 【问题描述】:

我正在 ASP.NET Core 证书身份验证中构建一个小功能,如 official docs 中给出的。

注意:我不是在构建 API,我只是想保护一些控制器的一些 Action 方法,以便这些安全的 action 方法只有在客户端有客户端证书。

下图显示我能够确保索引操作 现在需要客户端证书的方法。其他动作方法 这是隐私不需要客户端证书。结果是 该索引操作确实在浏览器中打开(收到 403 错误)但是 在浏览器中打开隐私操作

完整代码

1.程序.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();

注意:索引操作方法需要客户端身份验证,而隐私不需要客户端证书。

问题: 我遇到的问题是:

    CertificateAuthenticationEvents & OnAuthenticationFailed 位于我未调用的 startup.cs 文件的 ConfigureServices() 方法上。我通过放置断点来检查它们,但没有达到断点。

    MyCertificateValidationService.cs 类ValidateCertificate() 方法也没有被调用。我也用断点检查过

请帮我实现证书授权。

更新

我在 C# 中创建了 2 个证书为 explained in this tutorial。它们是:

    名为 root_localhost.pfx 的根证书 名为 client.pfx 的客户端证书

我用这些证书做了两件事:

一个。我将 root_localhost.pfx 添加到本地计算机的受信任的根证书颁发机构(在 Windows 上)(使用 CertManager)。

b.我通过 chrome 浏览器导入了客户端证书。

接下来,我选择了 VS 2019(控制台)中的项目而不是“IIS Express”并运行我的项目。我在隐身窗口打开网址,网址恰好是-https://localhost:5001

Chrome 要求选择证书,见下图:

选择它时,我得到 无法访问此站点 - ERR_SPDY_INADEQUATE_TRANSPORT_SECURITY,见下图:

为什么会这样????

【问题讨论】:

您是否已将浏览器配置为使用客户端证书? 【参考方案1】:

目前您的应用程序未配置为使用客户端证书。原因是您在 IIS Express 中启动(托管)应用程序。有两种选择:

1) 最简单的一种,切换到项目模式下运行(应用程序将在控制台窗口中运行)。您也可以在控制台中手动运行它。

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 实例。如果您希望它要求选择要使用的证书,请打开一个新的隐身窗口。

【讨论】:

当我在 VS 2019 中切换项目模式时,我得到“无法访问此站点”和“ERR_SPDY_INADEQUATE_TRANSPORT_SECURITY”。请推荐? 您使用哪个网址访问该网站?对于项目模式,它通常是 localhost:5001 或类似的。如果您未将本地服务器证书或您使用的其他证书添加到受信任的根目录,则应启用导航到此站点。单击警告下的高级链接。任何屏幕截图也可能有助于了解您的问题。 问题可能在某种程度上是您创建这些证书的方式。让我们分步进行。 1)如果您使用它,请从项目中删除您的根证书。运行由 VS 创建的 localhost 证书的项目。它应该询问您是否要添加为根证书,您可能会同意。 2)如果其余部分都很好并且您访问您的站点,它应该要求您选择客户端证书或返回错误(403) 3) 如果到目前为止一切顺利,请按照我的描述创建一个客户端自签名证书,并将其添加到 chrome 和根证书存储中。访问该站点,选择此添加的证书,您应该可以访问该站点。如果某些事情不像描述的那样工作,请记录错误并且不要移动到下一步。如果您成功通过了第 3 步,则意味着它可以使用简单的证书,您可能会开始创建更复杂的证书。 我相信这个问题可能与您如何创建证书、锁定图标上的小鸡以及查看您使用的证书有关。此外,它可能是相关的:***.com/questions/53086676/…support.microsoft.com/en-us/help/187498/…【参考方案2】:

我最近遇到了同样的问题并成功解决了。 您正在运行的测试项目存在两个问题。

    正如其他开发人员所说,应使用以下 sn-p 关闭吊销模式。
                
                    options.RevocationMode = X509RevocationMode.NoCheck; 

    使用下面的 sn-p 在 DI (ConfigureServices) 中注册 MyCertificateValidationService。 services.AddTransient&lt;MyCertificateValidationService&gt;();

一旦您做出这些更改,您的断点应该会命中 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;
        
    

【讨论】:

【参考方案3】:
options.RevocationMode = X509RevocationMode.NoCheck

设置这个对我有用

【讨论】:

放在哪里? 在此行之前 options.Events = new CertificateAuthenticationEvents in startup.cs【参考方案4】:

我最近也不得不处理这个问题,并记录了我的步骤here。它们很长,因此我建议您查看自述文件并按照说明进行操作。

无论如何我都会在这里为感兴趣的人发布主题:


证书

    运行文件 certcrt.cmd 并按照说明创建 .cer、.pfx 和 .crl 文件。 将客户端证书导入Current User\Personal。这通常在创建期间完成。
      Windows+R 输入 certmgr.exe 然后回车 右键个人 所有任务 > 导入 选择生成的.cer客户端文件
    将服务器证书导入Local Computer\Trusted Root Certitificates Authorities
      Windows+R 键入 certlm.exe 然后 Ctrl+Shift+Enter(以管理员身份启动) 右键单击受信任的根证书颁发机构 所有任务 > 导入 选择生成的.cer文件
    导入证书吊销列表。同上,但选择.crl文件

IIS/IIS Express

运行文件iis.cmd 更新相关配置部分。 iisClientCertificateMappingAuthentication 部分必须启用,access 部分应将 sslFlags 设置为“Ssl, SslNegotiateCert, SslRequireCert”`。

应用

    添加Microsoft.AspNetCore.Authentication.Certificatenuget包

    配置认证协议

    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;
                 
             ;
         );
    

    app.UseAuthorization() 之前添加app.UseAuthentication() 以挂钩CertificateAuthenticationEvents.OnCertificateValidated。这永远不会以其他方式调用,对任何证书都是开放的。

问题

HTTP 错误 403.16 - 禁止 您的客户端证书不受信任或无效。

参见证书第 2 步。

警告:证书验证失败,主题为 CN=ancc_client。 RevocationStatusUnknown 吊销函数无法检查证书的吊销。

查看证书第 3 步或禁用恢复检查options.RevocationMode = X509RevocationMode.NoCheck

【讨论】:

【参考方案5】:

以下是唯一需要做的事情,只是为了在调用 localhost 自签名时绕过证书错误。 请注意,我是构造函数注入 HttpClient (as described in here) 在 StartUp 类中,

  public void ConfigureServices(IServiceCollection services)
               

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

           

我从这篇文章中获得了上述验证覆盖:Custom certificate validation in .NET。

【讨论】:

以上是关于ASP.NET Core 3.1 中的证书身份验证实现的主要内容,如果未能解决你的问题,请参考以下文章

如何在 ASP.NET Core 3.1 中启用多重身份验证?

ASP.NET Core 3.1 Azure AD 身份验证引发 OptionsValidationException

使用两个 JWT 身份验证方案,ASP.NET Core 3.1

尝试对 ASP.NET Core 3.1 使用多个身份验证方案时出现异常

使用 ADFS 的 JWT Bearer 身份验证将 ASP.NET Framework 迁移到 ASP.NET Core 3.1

在 asp.net core 3.1+ 中使用多个中间件进行身份验证和授权