自托管 Asp Net Core Web 服务器,使用自签名证书进行客户端身份验证

问题描述 投票:0回答:2

我正在测试一个自托管的 Asp Net Core Web 服务器(Kestrel),并且我正在努力使用自签名证书进行客户端身份验证。 这是我的启动代码

WebApplicationBuilder webBuilder = WebApplication.CreateBuilder();
var webHostBuilder = builder.WebHost;

X509Certificate2 rootCert = new X509Certificate2(hostCertFilePath, hostCertPassword);

webHostBuilder.ConfigureKestrel(o =>
{
    o.ConfigureHttpsDefaults(o =>
    {
        o.ServerCertificate = rootCert;
        o.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
    });
});

webHostBuilder.UseKestrel(o =>
{
    o.Listen(IPAddress.Parse(myHttpsEndPointIpAddr), myHttpsEndPointPort,
        listenOptions =>
        {
            listenOptions.UseHttps();
        });
    o.Listen(IPAddress.Parse(myHttpEndPointIpAddr), myHttpEndPointPort);
});

var services = webBuilder.Services;

services.AddTransient<MyCustomCertificateValidationService>();
services
    .AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme)
    .AddCertificate(options =>
    {
        options.AllowedCertificateTypes = CertificateTypes.SelfSigned;
        options.Events = new CertificateAuthenticationEvents
        {
            OnCertificateValidated = context =>
            {
                var validationService = context.HttpContext.RequestServices
                    .GetService<MyCustomCertificateValidationService>();

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

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

...

var app = webBuilder.Build();

app.UseStaticFiles();
app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.UseEndpoints(endpoints => { endpoints.MapControllers(); });

这是我的定制认证课程

public class MyCustomCertificateValidationService
{
    public bool ValidateCertificate(X509Certificate2 clientCertificate)
    {
        // todo: check certificate thumbnail
        return false;
    }
}

但是,即使 MyCustomCertificateValidationService 有一个返回 false 的方法 ValidateCertificate(),当客户端通过控制器方法的路由访问 url 时,仍然会调用控制器方法。 这是日志中显示的内容:

...
AspNetCore.Routing.EndpointRoutingMiddleware : Request matched endpoint ‘GetMyData…‘
AspNetCore.Authentication.Certificate.CertificateAuthenticationHandler : Certificate was not authenticated. Failure message: invalid cert
AspNetCore.Routing.EndpointMiddleware : Executing endpoint ‘GetMyData…‘
...

知道为什么控制器方法仍然被调用吗?

c# asp.net-core ssl-certificate kestrel-http-server ssl-client-authentication
2个回答
0
投票

“该应用程序有一个用例,在某些测试环境中 还应该允许未经授权的调用(通过 http://...)。我会 如果可能的话,更喜欢使用设置参数来动态决定 如果允许或不允许 http 访问,而不是将其“硬编码”为 [授权]属性”

当然可以。当然,有一种方便的方法可以使用middleware来实现您的需求。请尝试下面的代码片段:

Http/Https请求中间件基于环境:

public class CustomHttpHttpsRequestMiddleware
    {
        private readonly RequestDelegate next;
        public CustomHttpHttpsRequestMiddleware(RequestDelegate next)
        {
            this.next = next;
        }
        public async Task InvokeAsync(HttpContext context)
        {
            var env = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
                //env = "Production";
            if (env == "Development")
            {
                await next(context);
            }
            else
            {
                if (!context.Request.IsHttps)
                {
                    context.Response.StatusCode = StatusCodes.Status400BadRequest;
                    await context.Response.WriteAsync("HTTPS required!");
                }
            }


        }
    }

注意:在应用程序中

request context
我们检查两个重要的值,首先如果请求是安全的意味着
cIsHttps
application environment
,在
Development
环境中我们将允许
http
请求。因此,除了
dev
或任何基于我们要求的
env
,我们将拒绝
http
请求。

在Program.cs上注册中间件:

app.UseMiddleware<CustomHttpHttpsRequestMiddleware>();

注意: 确保您遵循了正确的中间件顺序。为了避免短路,您可以将此中间件放在当前所有中间件的下方。

输出:


0
投票

您必须在 appsettings.json

中仅配置 HTTPS
{
   "Kestrel": {
      "EndPoints": {
         "Https": {
            "Url": "https://<IP>:<PORT>"
         }
      }
    }
 }

另外,需要在 Program.cs

中强制执行 HTTPS
app.UseHttpsRedirection();
© www.soinside.com 2019 - 2024. All rights reserved.