Require SSL Client Certificate only for specific routes or controllers

北城以北 提交于 2019-12-12 07:47:59

问题


I have an ASP.NET MVC Core project using Kestrel as the server. It is both serving up user content (asp.net mvc) and hosts web API controllers that agents (software) communicate with. I have enabled HTTPS and client certificate support. The issue is that I want to require client certificates for agents (software) that call Web APIs but I do not want to require/prompt for client certificates for regular browser based users.

I have enabled HTTPS/client certificate support the following way:

var host = new WebHostBuilder()
.UseKestrel(options =>
{
    HttpsConnectionFilterOptions httpsoptions = new    HttpsConnectionFilterOptions();
    httpsoptions.ServerCertificate = CertUtil.GetServerCert();
    httpsoptions.ClientCertificateMode = ClientCertificateMode.AllowCertificate;
    httpsoptions.CheckCertificateRevocation = false;

    options.UseHttps(httpsoptions);
})
.UseUrls("http://0.0.0.0:5000", "https://0.0.0.0:5001")
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.Build();
host.Run();

I have a separate middleware handler setup in Startup.cs to handle custom verification of client certificates. This code does successfully execute and everything works fine in that sense.

The problem is this happens globally and I am only looking to apply client certificates to specific controllers and/or routes; or really I would take any granularity at this point.

Essentially trying to create the same sort of behavior you can get in IIS by creating two virtual directories and then setting SSL Settings to Accept on one and Ignore on the other. The one with Accept will prompt the browser for a cert and the one with Ignore will not.

I tried setting HttpsConnectionFilterOptions to only specify ServerCertificate in hopes that not setting any client certificate related options would allow the server to receive client certificates if they are sent but otherwise not prompt browsers for them. This did not seem to work as my middleware client certificate handler never sees a client cert when calling this function (it does when ClientCertificateMode is set to AllowCertificate.

context.Connection.GetClientCertificateAsync();

I guess in short does Kestrel hosting even allow for more granular client certificate mapping/handling or is it only possible using IIS? IIS is not an option for this project and I would rather prefer not having to create a separate project/process just for the client cert api aspects. Appreciate any help!


回答1:


I've been trying to do the same thing, with exactly the same requirements as you.

I've come to the conclusion that it's not possible. My workaround is to use 2 WebHostBuilder objects - one for locations that don't need client certs, and one for those that do. This does have the downside that each IWebHost must listen on a different port, but from the scenario you describe I guess that's not a big issue.

I do this within the same process, so this solution fits that requirement.




回答2:


I had the same issue with context.Connection.GetClientCertificateAsync(); it was always returning null. Then I noticed that I was running Kestrel thru IIS Express all the time.

So in Visual Studio from the Debuger toolbar I changed from IIS Express to my project. Kestrel was started as console application and I was able to get the client certificate.

I think that IIS Express does not support client certificates so the certificate was always ignored.

For the other part of the question; I think Kestrel dos not support this granularity that you are looking out of the box when using the HttpsConnectionFilterOptions. From the Kestrel Connection Filter Options source code the connection will be dropped if the client certificate is null. Maybe you can modify the source code for the HttpsConnectionFilterOptions and create your own filter from it. Then you can use the ClientCertificateValidation property to specify custom certificate validation method that will allow the connection when no client certificate is send.

Hope this helps.




回答3:


I have figured out how to have Client Certificate only on some routes but when run in Azure Web App, the client cert is not being passed to the code. It is the same problem when running under IIS Express.

In this example, One controller needs no cert, the other two requires different certs. https://github.com/xavierjohn/ClientCertificateMiddleware

The certificate does get passed through if it is not run under IIS Express.




回答4:


There is no need to use isolated (new one) IWebHost to control access to dedicated MVC controllers. Just use MVC Filter for this purpose.



来源:https://stackoverflow.com/questions/38665934/require-ssl-client-certificate-only-for-specific-routes-or-controllers

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!