Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • JavaScript • Angular
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
Markdown Monster - The Markdown Editor for Windows

Work around localhost unsecured HTTPS access for Development Sites in Edge


:P
On this page:

Microsoft Edge in recent versions has gotten really annoying when it comes to accessing local Dev sites for development. The problem appears to be that Edge automatically forces http:// requests to https:// and then no longer allows bypassing an invalid local dev certificate as other Chromium browsers allow you to do (and Edge used to).

Depending on what development tools you use this may or may not be a problem. If you're using .NET Server development you can easily set up local development certificates and install them via the dotnet dev-certs https import command. Once installed https:// connections just work locally using the Kestrel Web server. Unfortunately other tools are not so complete.

I've been working with a Vue application lately and have been muddling through the lack of a valid certificate - partly because I've been too lazy to figure out how to install a certificate. I've been using one of the hacks described below to get around the limitations in Edge.

This post describes some of the issues with the requirements that Edge has for using https:// on localhost and for working with https:// requests if you don't have certificate installs and that cannot be easily just ignored in Edge.

Localhost HTTPS Hell in Edge

There are a couple of problems with Edge's handling of the Vue server:

  • Doesn't allow to override an Invalid Certificate
  • Doesn't allow access to a plain http://localhost URL

No way to Escape from Invalid HTTPS Certificate on Localhost

So my scenario is that I'm working on a local Vue application and when I launch the local Vite server I see this on localhost:

Note that I'm using:

vite --https

Now I don't really need to run in https:// but Edge (and Chromium browsers in general) now automatically redirect to https:// - even on localhost. So --https is essentially required (more on that in a moment).

In effect I have to run the server using https:// but I don't have a certificate and the screen above is what I get in Edge. Now I'm fully aware that there should be a security error since there's no certificate present, but in the past you were able to bypass this error via an advanced options link that explicitly asked, if I'm sure I want to take life in my own hands 😄 :

Yes, damn it! I like to live on the Edge. But Edge won't let me actually live on the Edge (ironic don't you think? 😜) - at least not with localhost.

The https:// certificate behavior on localhost seems to be specific to Edge, as using Brave (another Chromium based browser) I can bypass the invalid certificate via the Advanced options override link. With Brave I can get to https://localhost:3000 without a valid certificate:

Not so in Edge!

So you might think - screw all this https:// bullshit, lets just use plain old http://. You Heathen, you! http:// is so frowned upon these days.

So for the Vite server, if I don't use the --https flag and serve plain http:// content, I have another problem: Going to http://localhost:3000 Edge immediately redirects me to https://localhost:3000 and then fails with a protocol error:

The error makes sense at the https:// link - the server is not serving https:// but Edge insists on going there, and then of course there's no response from port 443.

The point is by default you really can't use http://localhost anymore as Chromium browsers always redirect to https://.

Heads you win, tails I lose!

The redirect behavior seems to be common to all Chromium Browsers now (FireFox also) so I think that's something we have to live with (but... why? why? why?).

https://localhost Rant

I'm happy with HTTP for public sites - these days with LetsEncrypt it's easy enough to create a certificate and install it. Fine!

But for localhost it's not quite a simple. Setting up certificates for a local site is a pain - especially for Windows. So why this insistence on making life more difficult when http:// would clearly suffice for a local development setup?

Solved: HSTS Caching for Localhost

As it turns out this the http:// redirection problem is not a universal problem, but related to a very specific problem with HSTS policy that is applied to all of localhost and cached if an application sets it.

Jesper Blad Jensen pointed this out on Twitter in reply to my post:

HSTS is a security policy that enforces certain security defaults including forcing requests from insecure to secure URLs (ie. http:// to https://). But as Jesper points out, the policy is applied to all applications that run on a given domain and - worse - cached!

This means if I run one application that uses HSTS - for example a server side ASP.NET application - it then sets this policy for all of localhost and caches that HSTS policy for all other applications I might be also running on localhost.

This effectively means that my local ASP.NET application just affected the HSTS policy for my local Vue/Vite application, even though the latter never used any HSTS policy settings at all.

Brilliant!

To fix this - again thanks to Jesper's suggestion - you can go to:

chrome://net-internals/#hsts

In the list of settings use the Delete domain security policies. Put in localhost (or any other domain) and press the Delete button:

Make sure to restart the browser. And voila - now the http://localhost works just fine.

This seems like a big fat design flaw. HSTS headers should not be cached and certainly not beyond the scope of the active session. The headers can and should be added to each request and then be processed accordingly. Even more appropriately a lot of these types of security (and cookie) policies should not be tied to the domain or worse the root domain, but to a very specific domain and port combination if applied. If caching of any sort is applied specificity should be a priority, but clear it's not in this case.

Ok - problem found and issue solved, but 🤦‍♂️.

With this in place I could now go back to using https://localhost:3000. But now that we're here, let's see if we can still using https://localhost:3000

Hackity Hack

On getting https:// to work on localhost.

There are a number of approaches that you can take which break down into two groups:

  • Bypass security and allow an invalid or missing certificate
  • Install an actual certificate

Edge: Use an explicit local IP Address

As mentioned Edge appears to not allow you to override invalid or missing certificates on localhost. Oddly it appears that Edge does allow other URLs than localhost to override an invalid certificate. If I run vite --https --host 0.0.0.0 which allows me to connect to a the local IP address, I can then bypass the HTTPS certificate:

So that's one way around this problem: Using http://192.168.50.240:3000 lets me get past the invalid HTTP certificate.

That makes perfect fucking sense, doesn't it? localhost - nope, 192.168.50.240 - yep. Brilliant!

thisisunsafe Security ByPass Hack

The next hack is a weird one: If you get a security dialog that you cannot bypass like the one above for localhost and https:// access with a certificate error in Edge, you can type thisisunsafe anywhere in the active browser window's Viewport.

If I do this I get through and now get the page to display with the broken https://localhost:3000 link in the address bar (ie. same behavior as with the dedicated IP Address except it now works with localhost):

Once you've done this the security setting is cached for some time so repeated restarts of the browser continue to bring up the page without the warning page. Note you still get the broken security lock (or whatever iconry your browser uses).

It works, but man, that is one hell of a hack!

Vue/Vite Specific: Use vite-plugin-mkcert

The next solution is probably the appropriate one to use, which is: Use a valid certificate!

There are lots of ways to do this, and you may already have a valid localhost certificate on your machine for IIS Express or for the ASP.NET Dev server that you could export and make available to another dev server like Vite for example. Not exactly simple especially if like me you're not very certificate-management-savvy and falter over certificate types and conversions.

Creating a certificate is easier said than done on Windows, where it's a major pain to create a new certificate and install it. But even on other platforms you have to do finger gymnastics with the SSH command to create or export a certificate and then use it with the server.

Luckily for the Vue application there's an easier way: There's a mkcert plugin that handles the entire process of creating a certificate, putting it in the local store, and automatically loading it when the server starts up.

The plug-in is called vite-plugin-mkcert and it creates and automatically installs a local dev certificate for localhost. You can install from NPM:

npm i vite-plugin-makecert -d

Then add the plugin config to the vite.config file:

import {fileURLToPath, URL} from 'url'

import {defineConfig} from 'vite'
import vue from '@vitejs/plugin-vue'

// *** THIS
import mkcert from 'vite-plugin-mkcert'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    // *** THIS
    mkcert()
  ],
  server: { https: true },  // *** THIS or use --https on the command line
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    },
  }
})

With the installed certificate, I now get a clean https:// Url in the browser, regardless which browser I use. Here's Edge:

This solution is Vite specific, but there are similar plug-ins for other dev pipelines like the Angular CLI etc.

Creating, and using a local client certificate that is trusted locally is the proper, puppy friendly way to handle local https:// certificates. No more warnings. So yay!

Another Option: LetsEncrypt and a local Web exposed domain name

Certificates don't need to be local client certificates of course - if you can tunnel to your local machine from the public Internet and map a domain name, you can also take advantage of standard public certificates like those created by LetsEncrypt.

I've used this approach in the past with my local 443 port mapped from the router to my dev machine and then mapping DNS to the router IP. Or you can use a dyanmic DNS service that does soemthing similar. Public DNS accessallows Web access to the machine and subsequently you can also register a public certificate that is Web verified.

Once the domain is Web visible, you can then use LetsEncrypt to create a public certificate and use that in the server configuration.

This is a bit of work, but is actually quite useful for quite a few different scenarios including easier testing with mobile devices which can then use a simple DNS name to find the local server without explicitly entering IP Addresses through a phone DNS entry app.

Summary

So in summary Edge is being relentlessly Edgy with https:// requests on localhost, more so than other Chromium browsers. The two problems are:

  • Always redirecting to http:// links https://
  • Not allowing to bypass https:// certificate errors on localhost

The former problem as described was due to the HSTS caching for the local domain and can be fixed by clearing the HSTS cache in the chrome://net-internals/#hsts settings. If you don't explicitly need https:// in your local Web application this is by far the least painful approach. However, if you're like me and you're running literally a dozen different applications on your machine - you likely will have a few that use HSTS so you'll continue to run into that nasty issue and will continually chase down the cache clearing which is hardly a solution.

So for me at least making https:// work is probably the best idea.

For getting https:// working, here's a summary of the work arounds discussed in this post:

  1. Use a different Chromium browser for localhost and bypass https:// warning
  2. Use a local fixed IP address in Edge (ie. 192.168.xxx.xxx) and bypass https:// warning
  3. Use thisisunsafe trick (type into browser) and bypass https:// warning
  4. Create a self-signed certificate for localhost and register with your server
  5. Map localhost to a Web accessible domain and install a LetsEncrypt Certificate
  6. Use a tooling plug-in to create and install a local self-signed cert (ie. vite-plugin-mkcert)

For me #6 was ultimately the cleanest, which works for the application I'm working on, but it's a specific solution to the Vue project I'm working on at the moment.

I've used #5 on quite a few occasions and that works well too if you can map a local IP or use dynamic DNS of some sort.

Onwards...

this post created and published with the Markdown Monster Editor
Posted in Web  WebBrowser  

The Voices of Reason


 

Thom
September 22, 2022

# re: Work around localhost unsecured HTTPS access for Development Sites in Edge

Another workaround using LetsEncrypt that doesn't involve tunneling to your local site, as long as you have access to the DNS for a site: let's say you're developing for a public site named www.whatever.com. Create a local development site with the URL development.whatever.com. Then use LetsEncrypt verification method of looking up a specific TXT record for the subdomain. When LetsEncrypt prompts you to add the specific txt string to the TXT record for the site's DNS, do so. It'll then add the SSL cert to your local site without ever having to allow external access to the site. I use https://www.win-acme.com/ to do this, but I suspect other methods might also support this.


Rick Strahl
September 22, 2022

# re: Work around localhost unsecured HTTPS access for Development Sites in Edge

@Thom - great tip - I have to try this with WinAcme... that would be a great and relatively easy way to create a local development certificate in general.


Thomas Levesque
September 22, 2022

# re: Work around localhost unsecured HTTPS access for Development Sites in Edge

HSTS headers should not be cached and certainly not beyond the scope of the active session

Actually, this is kind of the point of HSTS... It ensures the website is always accessed via HTTPS after the first visit (or even for the first visit thanks to HSTS Preload list). But maybe there should be an exception for locahost, since it's typically used for development purposes...


Rick Strahl
September 23, 2022

# re: Work around localhost unsecured HTTPS access for Development Sites in Edge

@Thomas - That seems unnecessary since the app can respond on first hit with an HSTS header and redirect. I get the immediate redirect is one extra step for potential attack vector, but there will always be at least 1 first request against the site anyway, so that risk is always there regardless of the caching.

Agreed though - I think the only place where this is really an issue these days is for a local dev site. So it sure would make sense for HSTS perhaps to be more lenient on local machine IP addresses (or even just localhost).


West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2022