簡體   English   中英

OnCertificateValidated 未運行 - 自簽名證書客戶端身份驗證 - ASP.NET Core 和 Kestrel

[英]OnCertificateValidated not running - Self-Signed Certificate Client Authentication - ASP.NET Core and Kestrel

我想使用基於證書的身份驗證對連接到在 Kestrel 上運行的 ASP.NET Core Web API (.NET 5) 的客戶端進行身份驗證。

在我的Startup.cs我在ConfigureServices有以下內容:

services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme)
    .AddCertificate(options =>
    {
        options.AllowedCertificateTypes = CertificateTypes.All;
        options.Events = new CertificateAuthenticationEvents
        {
            OnCertificateValidated = context =>
            {
                // More code to verify certificates
            },
            OnAuthenticationFailed = context =>
            {
                // More code
            }
        };
    });

// Other services

Configure

app.UseHttpsRedirection();

app.UseRouting();

app.UseAuthentication();

app.UseEndpoints(endpoints =>
{
    // Endpoints
});

Program.cs我包含了:

webBuilder.ConfigureKestrel(o =>
{
    o.ConfigureHttpsDefaults(o =>
        o.ClientCertificateMode = ClientCertificateMode.RequireCertificate);
});

如果我連接到API的瀏覽器,它提示我要證書,但我選擇一個證書后,無論是OnCertificateValidated也不OnAuthenticationFailed事件被觸發。 經過一些進一步的測試,我意識到Startup.cs AddCertificate調用中的整個選項配置委托永遠不會運行。 這讓我覺得我缺少某種 Kestrel 的配置,但我不知道那是什么。 請注意,我的 Web API 不使用 IIS 托管。 我還需要做什么才能使用基於自簽名證書的身份驗證?

到目前為止,我擁有的代碼基於此處文檔中的說明: https : //docs.microsoft.com/en-us/aspnet/core/security/authentication/certauth?view=aspnetcore-5.0

好的,所以最后我能夠解決我自己的問題。 解決它有兩個不同的部分,但最終只需要對我的項目代碼進行一些小的修改。

識別客戶端證書

首先,服務器未將自簽名客戶端證書識別為有效證書。 這可以通過以下任一方式解決: 1. 將所有客戶端證書(或對所有證書進行簽名的根 CA)添加到操作系統的可信證書存儲中,或者 2. 將ClientCertificateValidation回調添加到 kestrel 以確定證書是否為接受或拒絕。

#2 的示例(對Program.csConfigureHttpsDefaults lambda 的調整)如下:

webBuilder.ConfigureKestrel(o =>
{
    o.ConfigureHttpsDefaults(opts =>
    {
        opts.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
        opts.ClientCertificateValidation = (cert, chain, policyErrors) =>
        {
            // Certificate validation logic here
            // Return true if the certificate is valid or false if it is invalid
        };
    });
});

作為旁注,調用opts.AllowAnyClientCertificate()是添加始終返回 true 的ClientCertificateValidation回調的簡寫,使所有自簽名證書都有效。


所需授權

應用這些方法之一后,我的 API 將接受來自有效證書的查詢,但我在OnCertificateValidated事件中的額外證書驗證邏輯仍未運行。 這是因為,根據對ASP.NET Core 問題 #14033 的評論,除非為正在訪問的端點啟用授權,否則此事件的額外證書驗證將永遠不會運行。 這是有道理的,因為此事件通常用於根據主題上的 ASP.NET Core Docs的證書生成ClaimsPrincipal 將 ASP.NET 設置為使用授權並要求對 API 調用進行授權(例如,通過將[Authorize]屬性應用於所有控制器)會導致對這些 API 調用運行額外的身份驗證檢查。

app.UseHttpsRedirection();

app.UseRouting();

app.UseAuthentication();

// Adding this and adding the [Authorize] attribute
// to controllers fixes the problem.
app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
    // Endpoints
});

在此之后,每個連接都會調用我的OnCertificateValidated事件,並且我能夠執行額外的身份驗證邏輯並拒絕無效證書。

接受的答案對我很有幫助(謝謝!)但它並沒有完全解決我的問題。

我發現ClientCertificateValidation函數不是驗證(和拒絕)證書的唯一地方。 使用AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme). AddCertificate... AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme). AddCertificate...還導致在處理ClientCertificateValidation之后觸發另一個驗證。

為了解決我的問題,我必須在CertificateAuthenticationOptions:行中配置CustomTrustStore CertificateAuthenticationOptions:

AddCertificate(options =>
{
    options.AllowedCertificateTypes = CertificateTypes.All;
    options.ChainTrustValidationMode = X509ChainTrustMode.CustomRootTrust;
    options.CustomTrustStore = new X509Certificate2Collection { rootCert };
    options.RevocationMode = X509RevocationMode.NoCheck;
    options.Events = new CertificateAuthenticationEvents
    {
        OnCertificateValidated = context =>
        {
            if (validationService.ValidateCertificate(context.ClientCertificate))
            {
                context.Success();
            }
            else
            {
                context.Fail("invalid cert");
            }

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

rootCert是通過以下方式啟動的:

var rootCert = new X509Certificate2("RootCert.pfx", "1234");

並且RootCert.pfx作為文件添加到項目中。

由於我們現在使用AddAuthentication(.).AddCertificate的內置驗證,我們應該使用AllowAnyCertificate()禁用較早的驗證(此驗證不知道我們的自定義根信任):

builder.WebHost.ConfigureKestrel(kso =>
{
    kso.ConfigureHttpsDefaults(cao => {
        cao.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
        cao.AllowAnyClientCertificate();
        cao.CheckCertificateRevocation = false;
    });
});

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM