question

jeff-bowman avatar image
0 Votes"
jeff-bowman asked jeff-bowman edited

Self-Hosted Blazor and Custom Certificates

I'm investigating the idea of using Blazor WASM to build a retail application that would run on an office Intranet. The application would be installed on a given machine, to be accessed via browser from any of several machines on the LAN.

The biggest stumbling block I'm running into is the question of how to go about securing the channel.

The app itself would run as a Windows Service, listening on port 443 on one of the workstations, e.g. https://reception/. But how do we tell Blazor to use a self-signed TLS cert for that hostname?

If there's a better way to go about this, I'm all ears. I can't use Let's Encrypt certs, because neither the application nor its hostname will be exposed to the public Internet.

There is a glut of information on working with Blazor to build such an app, but most if not all demos run on localhost. That works fine for dev, but not for production (in a self-hosting scenario, anyway). There doesn't seem to be much discussion at all of this aspect of things.

How can we use a custom certificate for browser requests from the client to a Blazor WASM app?

Any ideas?

dotnet-aspnet-core-blazor
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

AgaveJoe avatar image
0 Votes"
AgaveJoe answered jeff-bowman edited

The app itself would run as a Windows Service, listening on port 443 on one of the workstations

In my opinion, IIS is much easier to configure and deploy to. Plus, IIS comes with Windows. I'm pretty sure you'll need to tweak Windows Defender or your virus checker to allow access to port 443 regardless of the service you decide to use.


But how do we tell Blazor to use a self-signed TLS cert for that hostname?

This is straight forward configuration in IIS.

173539-capture.png

I would use the computer name to create the certificate. DNS is required to register domains otherwise you must update all the client's hosts file if you want to use https://reception. If you go with the DNS or hosts file route then use "reception" when creating the certificate. The domain and the certificate must match otherwise the browser will report a warning.

Generate self-signed certificates with the .NET CLI
Host ASP.NET Core in a Windows Service



capture.png (10.9 KiB)
· 3
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Thank you, Joe, but I failed to mention that this is a retail application, to be sold at market. Thus, I have no control over machine configurations such as IIS, SQL, etc.

Not only that, my target audience doesn't (and won't) possess the technical acumen necessary to perform such a configuration. Setup must all be automated, and there're too many moving parts for me to want to try to automate an IIS installation.

Someone mentioned Kestrel's ListenOptions.UseHttps() extension methods as a possible way to specify a custom certificate.

Would you agree?

Thanks,
Jeff Bowman
Fairbanks, Alaska


1 Vote 1 ·

Hi Jeff. Did you manage to accomplish this?

0 Votes 0 ·
jeff-bowman avatar image jeff-bowman GuillermoPrieto-8523 ·

I did manage to solve it somewhat, but not without opening a different Pandora's box of trouble.

For starters, here's the Kestrel code I ended up with:

 WebApplicationBuilder? oBuilder;
 WebApplication? oApp;

 oBuilder = WebApplication.CreateBuilder();
 oBuilder.Services.AddControllersWithViews();
 oBuilder.Services.AddRazorPages();
    
 oBuilder.WebHost.ConfigureKestrel(ServerOptions =>
 {
   ServerOptions.ListenAnyIP(443, ListenOptions =>
   {
     ListenOptions.UseHttps(HttpsOptions =>
     {
       HttpsOptions.ServerCertificateSelector = (ConnectionContext, CommonName) =>
       {
         return Utils.GetServerCertificate();
       };
     });
   });
 });

 oApp = oBuilder.Build();

 public class Utils
 {
     public static X509Certificate2 GetServerCertificate()
     {
        // ... Create/load certificate here
     }
 }

And this works (it runs on every page load), but client browsers won't automatically trust a self-signed cert. And forget trying to require your users to install a Root CA. Ever try to herd cats?

I spent a good few days digging around, and the best solution I was able to find is Let's Encrypt certs using DNS validation (since the Blazor app is self-hosted on the private LAN). I haven't yet gotten to that part of the code base, so I don't have any advice to offer there. (Note that I had ruled out Let's Encrypt in my original question, but I hadn't considered the DNS validation option at that time.)

HTH

0 Votes 0 ·
Bruce-SqlWork avatar image
0 Votes"
Bruce-SqlWork answered jeff-bowman commented

note, all you users will need to trust the self signed certificate (if their security setting allow this). Check your networking group. They may have created and installed a self signing authority that you can use to generate the certificate. You can also buy a valid certificate.


· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Thank you, Bruce, for your good advice.

Yes, I'll be providing a way for everyone to install the Root CA to which the server certificate will be linked. I can probably accomplish that via a separate ClickOnce deployment.

Note that this is a retail application, not a one-off, so setup has to be highly automated.

Thanks,
Jeff Bowman
Fairbanks, Alaska

1 Vote 1 ·
Bruce-SqlWork avatar image
0 Votes"
Bruce-SqlWork answered jeff-bowman commented

reading your question closer, Blazor WASM works like any web page. the WASM is just a resource loaded into the browser via an ajax call from the index.html. so the link to the index page should be https. blazor WASM just uses the javascript's ajax support for WebClient, so the ajax urls just need to be https. typically you set the base url in the index.html, and use relative links. The browser supplies all the https support, and you configure the browser to support your blazor hosting website.

if you are using a separate webapi site, then be sure to enable CORS, and use https:

in short you configure the blazor hosting website as https, just as if it was a regular website.

note: blazor wasm is in a sandbox and can not directly access the internet, filesystems or the browser dom. it uses javascript interop to do this. to the browser, a blazor app is just a html/javascript app that loads a WebAssembly.

· 3
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Thanks, that helps my understanding a little bit better. As you can probably tell, I'm new to Blazor.

Someone mentioned Kestrel's ListenOptions.UseHttps() extension methods as a possible way to specify a custom certificate.

Would you agree?

Thanks,
Jeff Bowman
Fairbanks, Alaska




0 Votes 0 ·

Depends on the hosting configuration. Typically if hosted by a proxy application, you configure the proxy application.

If hosting on windows with IIS, you use IIS to configure ssl certificates. If on Linux and using ngnix then you use ngnix if hosted in the cloud, typically there is a registration step.

If you are running the core app directly, then you use the link you provided.

0 Votes 0 ·

Looks like that about covers it!

Thanks,
Jeff Bowman
Fairbanks, Alaska

0 Votes 0 ·