添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
爱运动的手电筒  ·  Spring boot + Spring ...·  3 月前    · 
谦和的皮带  ·  腾讯体育-社区·  3 月前    · 

In this article, I would share a .NET 6.0 Web API sample code that supports Client certificate authentication. The sample code utilizes the build-in feature of .NET Microsoft.AspNetCore.Authentication.Certificate that is SIMILAR to Certificate Request of Handshake Protocol written in The Transport Layer Security Protocol (RFC5246).

  • Web Server requires a client certificate and validate the certificate is trusted during TLS handshake.
  • CertificateAuthenticationOptions handler checks the certificate type. CertificateValidationService validates the pfx file or thumbprint.
  • Controller has to have [Authorize] attribute because it deals with the context determined in TLS handshake and Authentication/Authorization middleware.
  • Configure Kestrel server for a local run so it requires a client certificate during TLS handshake
  • Microsoft.AspNetCore.Server.Kestrel.Https.ClientCertificateMode has options such as RequireCertificate and AllowCertificate . Once you set RequireCertificate , any request without a client certificate is declined.
  • A self-signed certificate does not work without AllowAnyClientCertificate() method.
  • Program.cs

    builder.Services.Configure<KestrelServerOptions>(options =>
        options.ConfigureHttpsDefaults(options =>
            options.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
            options.AllowAnyClientCertificate();
        Enter fullscreen mode
        Exit fullscreen mode
    
  • When the application code is deployed in Azure App Service, it requires another Web Server configuration than Kestrel in Program.cs.
  • Azure App Service has configuration that accepts and requires a client certificate in the request from the client application.
  • Set clientCertEnabled: true and clientCertMode: 'Required' in your bicep file.
  • It looks you do not need to specify self-signed certificate for Azure App Service.
  • Bicep example

    resource AppServiceCert 'Microsoft.Web/sites@2021-03-01' = {
      name: appsrv_name_cert
      location: location
      kind: 'app'
      identity: {
        type: 'SystemAssigned'
      properties: {
        serverFarmId: AppServicePlanCert.id
        httpsOnly: true
        clientCertEnabled: true
        clientCertMode: 'Required'
        siteConfig: {
          netFrameworkVersion: '6.0'
          http20Enabled: true
          minTlsVersion: '1.2'
        Enter fullscreen mode
        Exit fullscreen mode
    
  • An event handler CertificateAuthenticationEvents is triggered during a TLS handshake, which is written with builder.Services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme) in Program.cs.
  • A self-signed certificate requires CertificateAuthenticationOptions.AllowedCertificateTypes property to be All or SelfSigned.
  • The CertificateAuthenticationOptions handler calls CertificateValidationService and set the context success or fail.
  • If the validation fails, it returns 403 forbidden during the TLS handshake before it reaches .NET application.
  • Program.cs

    builder.Services.AddAuthentication(
            CertificateAuthenticationDefaults.AuthenticationScheme)
        .AddCertificate(options =>
            options.AllowedCertificateTypes = CertificateTypes.All;
            options.Events = new CertificateAuthenticationEvents
                OnCertificateValidated = context =>
                    var validationService = context.HttpContext.RequestServices
                        .GetRequiredService<ICertificateValidationService>();
                    if (validationService.ValidateCertificate(context.ClientCertificate))
                        context.Success();
                        context.Fail("Invalid certificate");
                    return Task.CompletedTask;
        Enter fullscreen mode
        Exit fullscreen mode
    CertificateValidationService handles the certificate validation and returns true/false to CertificateAuthenticationOptions handler.
    
  • To validate an incoming client certificate, the Web API app config has Pfx file path and Pfx password, or the certificate thumbprint.
  • If the Web API instance does not have the Pfx file, for example, if it is deployed in Azure App Service, the service validates if the incoming certificate thumbprint is identical with the one in the app config.
  • CertificateValidationService

    public bool ValidateCertificate(X509Certificate2 clientCertificate)
        X509Certificate2 expectedCertificate;
        string pfxFilePath = this.configuration.GetValue<string>("Certificate:PfxFilePath");
        string pfxFilePassword = this.configuration.GetValue<string>("Certificate:PfxFilePassword");
        if (File.Exists(Path.Combine(Directory.GetCurrentDirectory(), pfxFilePath)))
            expectedCertificate = new X509Certificate2(
                Path.Combine(Directory.GetCurrentDirectory(), pfxFilePath), pfxFilePassword);
            return clientCertificate.Thumbprint == expectedCertificate.Thumbprint;
            return clientCertificate.Thumbprint == this.configuration.GetValue<string>("Certificate:Thumbprint");
        Enter fullscreen mode
        Exit fullscreen mode
    

    For local run, you will set the Pfx file path and password or thumbprint in appsettings.json or appsettings.Development.json

    appsettings.json example

    "Certificate": {
       "PfxFilePath": "certificates/sample.pfx",
       "PfxFilePassword": "{Pfx file password if needed}",
       "Thumbprint": "6B132..."
        Enter fullscreen mode
        Exit fullscreen mode
    
  • It is difficult to have the Pfx file in Azure App Service, and then it can validate with the thumbprint.
  • The thumbprint should be stored in Azure Key Vault and the App Service extracts it through Key Vault reference.
  • Bicep example

    resource AppServiceConfigCert 'Microsoft.Web/sites/config@2021-03-01' = {
      name: '${AppServiceCert.name}/appsettings'
      properties: {
        'Certificate:PfxFilePath': ''
        'Certificate:PfxFilePassword': ''
        'Certificate:Thumbprint': '@Microsoft.KeyVault(VaultName=${kv_name};SecretName=${kvsecret_name_cert_thumbprint})'
        'WEBSITE_RUN_FROM_PACKAGE': 1
        Enter fullscreen mode
        Exit fullscreen mode
    
  • It seems bash does not have a feature to send a pfx file. So I tried with a cert file and private key.
  • Powershell supports sending a pfx file. It requires a password after calling Invoke-RestMethod, if needed.
  • curl {App URL}/Weatherforecast/RequireAuth \
       --cert ./sample.crt \
       --key ./sample.key \
       --insecure
        Enter fullscreen mode
        Exit fullscreen mode
        Method  = 'GET'
        Uri     = '{App URL}/Weatherforecast/RequireAuth'
        Certificate  = (Get-PfxCertificate '.\sample.pfx')
    Invoke-RestMethod @parameters
        Enter fullscreen mode
        Exit fullscreen mode
    

    Private key: sample.key
    Public key: sample_public.key
    Crtificate signing request: sample.csr
    Certificate(PEM): sample.crt
    Certificate(PKCS#12): sample.pfx

    Create a private key

    openssl genrsa -out sample.key 2048
        Enter fullscreen mode
        Exit fullscreen mode
          

    Built on Forem — the open source software that powers DEV and other inclusive communities.

    Made with love and Ruby on Rails. DEV Community © 2016 - 2024.