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,它会提示我输入证书,但是在我 select 证书之后,OnCertificateValidated
和 OnAuthenticationFailed
事件被触发。经过进一步测试,我意识到 Startup.cs
中 AddCertificate
调用中的整个选项配置委托从未运行。这让我觉得我缺少 Kestrel 的某种配置,但我不知道那是什么。请注意,我的网站 API 不使用 IIS 托管。我还需要做什么才能使用基于证书的自签名身份验证?
我目前的代码基于此处文档中的说明:https://docs.microsoft.com/en-us/aspnet/core/security/authentication/certauth?view=aspnetcore-5.0
好的,所以最后我能够解决我自己的问题。解决它有两个不同的部分,但最终只需要对我的项目代码进行一些小的修改。
正在识别客户端证书
首先,服务器未将自签名客户端证书识别为有效证书。这可以通过 1. 将所有客户端证书(或对它们全部签名的根 CA)添加到操作系统的受信任证书库或 2. 向 kestrel 添加 ClientCertificateValidation
回调以确定是否或没有证书被接受或拒绝。
#2 的示例(对 Program.cs
中的 ConfigureHttpsDefaults
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()
是一个 shorthand,用于添加一个 ClientCertificateValidation
回调,该回调始终 returns 为真,使所有自签名证书都有效。
需要授权
应用这些方法中的任何一种后,我的 API 将接受来自有效证书的查询,但我在 OnCertificateValidated
事件中的额外证书验证逻辑仍然没有 运行ning。这是因为,根据 ASP.NET Core issue #14033, this event's extra certificate validation will never run unless authorization is enabled for the endpoint being accessed. This makes sense because this event is often used to generate a ClaimsPrincipal
from a certificate per the ASP.NET Core Docs on the subject 的评论。将 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
函数不是唯一验证(和拒绝)证书的地方。在处理 ClientCertificateValidation
之后,使用 AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme). AddCertificate...
还会触发另一个验证。
为了解决我的问题,我必须在 CertificateAuthenticationOptions:
的行中配置一个 CustomTrustStore
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;
});
});
我想在 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,它会提示我输入证书,但是在我 select 证书之后,OnCertificateValidated
和 OnAuthenticationFailed
事件被触发。经过进一步测试,我意识到 Startup.cs
中 AddCertificate
调用中的整个选项配置委托从未运行。这让我觉得我缺少 Kestrel 的某种配置,但我不知道那是什么。请注意,我的网站 API 不使用 IIS 托管。我还需要做什么才能使用基于证书的自签名身份验证?
我目前的代码基于此处文档中的说明:https://docs.microsoft.com/en-us/aspnet/core/security/authentication/certauth?view=aspnetcore-5.0
好的,所以最后我能够解决我自己的问题。解决它有两个不同的部分,但最终只需要对我的项目代码进行一些小的修改。
正在识别客户端证书
首先,服务器未将自签名客户端证书识别为有效证书。这可以通过 1. 将所有客户端证书(或对它们全部签名的根 CA)添加到操作系统的受信任证书库或 2. 向 kestrel 添加 ClientCertificateValidation
回调以确定是否或没有证书被接受或拒绝。
#2 的示例(对 Program.cs
中的 ConfigureHttpsDefaults
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()
是一个 shorthand,用于添加一个 ClientCertificateValidation
回调,该回调始终 returns 为真,使所有自签名证书都有效。
需要授权
应用这些方法中的任何一种后,我的 API 将接受来自有效证书的查询,但我在 OnCertificateValidated
事件中的额外证书验证逻辑仍然没有 运行ning。这是因为,根据 ASP.NET Core issue #14033, this event's extra certificate validation will never run unless authorization is enabled for the endpoint being accessed. This makes sense because this event is often used to generate a ClaimsPrincipal
from a certificate per the ASP.NET Core Docs on the subject 的评论。将 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
函数不是唯一验证(和拒绝)证书的地方。在处理 ClientCertificateValidation
之后,使用 AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme). AddCertificate...
还会触发另一个验证。
为了解决我的问题,我必须在 CertificateAuthenticationOptions:
CustomTrustStore
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;
});
});