如何配置IIS以定义路由使端点路径不同于物理路径时特定端点上所需的客户端证书

j1dl9f46  于 2023-01-13  发布在  其他
关注(0)|答案(3)|浏览(143)

我实现了一个dotnet核心API,其中端点是基于Controller属性Route定义的。
我想配置IIS,以便忽略controller 1的客户端证书,而controller 2需要客户端证书。在我的API中,我这样实现了主机

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>()
            .ConfigureKestrel(o =>
            {
                o.ConfigureHttpsDefaults(o=>o.ClientCertificateMode=ClientCertificateMode.AllowCertificate);
            })
            .UseIISIntegration()
            .ConfigureLogging(logging =>
            {
                logging.ClearProviders();
                logging.SetMinimumLevel(LogLevel.Debug);
            })
            .UseNLog();

和配置的服务

services.AddSingleton<CertificateValidationService>();

    services.Configure<IISOptions>(options =>
    {
        options.ForwardClientCertificate = true;
    });
    services.AddAuthentication()
        .AddCertificate(x =>
        {
            x.AllowedCertificateTypes = CertificateTypes.All;
            x.ValidateValidityPeriod = true;
            x.RevocationMode = X509RevocationMode.NoCheck;
            x.Events = new CertificateAuthenticationEvents
            {
                OnCertificateValidated = context =>
                {
                    _logger.Trace("Enters OnCertificateValidated");
                    var validationService =
                        context.HttpContext.RequestServices.GetService<CertificateValidationService>();
                    if (validationService.ValidateCertificate(context.ClientCertificate))
                    {
                        _logger.Trace("OnCertificateValidated success");
                        context.Success();
                    }
                    else
                    {
                        _logger.Trace("OnCertificateValidated fail");
                        context.Fail("invalid certificate");
                    }

                    return Task.CompletedTask;
                },
                OnAuthenticationFailed = context =>
                {
                    _logger.Trace("Enters OnAuthenticationFailed");
                    context.Fail("invalid certificate");
                    return Task.CompletedTask;
                }
            };
        });

下面是Startup.cs的Configure方法中的中间件管道配置

if (env.IsLocal())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler(appBuilder =>
            {
                appBuilder.Use(async (context, next) =>
                {
                    var error = context.Features[typeof(IExceptionHandlerFeature)] as IExceptionHandlerFeature;
                    if (error != null && error.Error is SecurityTokenExpiredException)
                    {
                        _logger.Warn($"No valid token provided. {error.Error.Message}");
                        context.Response.StatusCode = 401;
                        context.Response.ContentType = "application/json";
                        await context.Response.WriteAsync(JsonConvert.SerializeObject(new
                        {
                            IpUrl = _globalSettings.IdP.Url,
                            SpName = _globalSettings.IdP.Name,
                            Authenticate = context.Request.GetEncodedUrl(),
                            //State = 401,
                            Msg = "Token expired"
                        }));
                    }
                    else if (error?.Error != null)
                    {
                        _logger.Error($"Unexpected error - {error.Error.Message}");
                        context.Response.StatusCode = 500;
                        context.Response.ContentType = "application/json";
                        await context.Response.WriteAsync(JsonConvert.SerializeObject(new
                        {
                            State = 500,
                            Msg = error.Error.Message
                        }));
                    }
                    else
                    {
                        await next();
                    }
                });
            });
            // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
            app.UseHsts();
        }
        app.UseHttpsRedirection();
        app.UseRouting();

        app.UseCors("AllowOrigin");
        app.UseAuthentication();
        app.UseAuthorization();

        app.UseSwagger(SwaggerHelper.ConfigureSwagger);
        app.UseSwaggerUI(SwaggerHelper.ConfigureSwaggerUi);

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

我尝试使用web.config位置,但“路径”API/controller 2实际上并不存在(它被路由了),因此没有效果
我在app文件夹中创建了faked API/controller 2文件夹来设置SSL要求。不幸的是,我得到了一个405,因为我丢失了路由,这些文件夹后面什么都没有。
我目前唯一的方法是在API应用程序级别“接受”证书,但是,我的前端在第一次查询时,我的API会在仅使用api/controller 1时请求证书
是否有办法或必须构建和部署特定的API来保护它,而另一个API不使用客户端证书?

2w3rbyxf

2w3rbyxf1#

不幸的是,这是不可能的。证书验证发生在TLS层,即在实际请求到达ASP.NET核心之前,所以你不能通过路由来区分。它甚至在你实现这样的逻辑之前就失败了。
我们遇到了类似的问题,我们必须设置两个应用程序,一个有证书验证,另一个没有。有证书验证的应用程序调用另一个应用程序进行“普通”(在我们的例子中是JWT机器对机器)身份验证,并传递证书参数。
这是official docu that states this

**我是否可以将我的应用配置为仅在某些路径上需要证书?**这是不可能的。请记住,证书交换是在HTTPS会话开始时完成的,它是由服务器在该连接上接收到第一个请求之前完成的,因此不可能基于任何请求字段来确定范围。

70gysomp

70gysomp2#

我也有类似的问题,我为iis express找到了一个解决方案,我认为iis也是类似的,我稍后会写这篇文章(如果它能起作用的话)。
但是关于溶液(起始条件):
1.我在舞台上测试从视觉工作室,我运行下集成在VS的iis表达净核心应用程序。
1.对于我的解决方案,我需要请求用户证书时,用户转到URL "/证书/应用/"(仅在此页面上)。
1.项目名称为"TestCore"
步骤:
1.在visual studio项目文件夹中,您需要找到隐藏文件夹. vs,在此文件夹中,您需要找到文件夹"config"和文件"applicationhost. config"
1.在此文件中,您需要找到与以下部分类似的项目配置:

<location path="TestCore" inheritInChildApplications="false">
 <system.webServer>
   <modules>
     <remove name="WebMatrixSupportModule" />
   </modules>
   <handlers>
     <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
   </handlers>
   <aspNetCore processPath="%LAUNCHER_PATH%" stdoutLogEnabled="false" hostingModel="InProcess" startupTimeLimit="3600" requestTimeout="23:00:00" />
   <httpCompression>
     <dynamicTypes>
       <add mimeType="text/event-stream" enabled="false" />
     </dynamicTypes>
   </httpCompression>
 </system.webServer>

1.在文件中克隆(复制-粘贴)此节并修改副本(更改路径并添加sequryti节):

<location path="TestCore/certificate/apply" inheritInChildApplications="false">
 <system.webServer>
     <modules>
         <remove name="WebMatrixSupportModule" />
     </modules>
     <handlers>
         <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
     </handlers>
     <aspNetCore processPath="%LAUNCHER_PATH%" stdoutLogEnabled="false" hostingModel="InProcess" startupTimeLimit="3600" requestTimeout="23:00:00" />
     <httpCompression>
         <dynamicTypes>
             <add mimeType="text/event-stream" enabled="false" />
         </dynamicTypes>
     </httpCompression>
     <security>
         <access sslFlags="SslNegotiateCert" />
     </security>
 </system.webServer>

1.尝试启动项目(对于mee,它工作正常).
我希望我(或其他人)会找到同样的方式为IIS。

7d7tgy0s

7d7tgy0s3#

对于IIS和IISExpress,这可以通过使用location元素来实现,我已经成功地使用了它,如下所示(这是添加在web.config中的configuration元素中的-请参阅here中的示例):

<location path="restapi">
  <system.webServer>
    <security>
        <access sslFlags="Ssl,SslNegotiateCert,SslRequireCert"/>
    </security>
  </system.webServer>
</location>

这意味着除restapi之外的任何路由,例如http://localhost/whatever,服务器将不要求客户端证书作为请求的一部分。一旦您点击http://localhost/restapi/whatever 2,就需要客户端证书(如果您从浏览器调用此命令,您将看到一个弹出窗口,要求您选择要发布的客户端证书)。
对于Kestrel,请查看Maxim Zabolotskikh提供的answer

相关问题