Browsers these days either mark sites with a padlock ( https://) or "not secure" ( http://). This warns the users that without the protection of " https://" your communications could be read or modified by any network your packets travel over. But how should " http://localhost" be marked? That's your own computer so it's secure, but the connection isn't encrypted so a padlock would be misleading.

It turns out that the browsers have three options for the url bar, not just secure and insecure. Here's what they look like in Firefox:

Chrome:

Safari:

Despite the unusual URL bar treatment, the major browsers do now all treat this configuration as a secure context (spec), which means you can use features that require secure contexts, like crypto, MIDI, or geolocation.

Comment via: facebook, mastodon

New Comment
3 comments, sorted by Click to highlight new comments since:

I'm actually pretty dissatisfied with how browsers are handling localhost, because they're neglecting the importance of the port. In Chrome, different localhost ports are treated as the same origin, including for purposes of things like tab-zoom. This becomes a problem as soon as you have more than one locally running webapp. (I had to write myself a browser extension workaround because my terminals are Chrome appmode, and I also develop a webapp, and zooming the webapp would also zoom all the terminals which is terrible). I think there are probably also security issues, if any of the localhost apps are at all untrusted.

Meanwhile Safari isn't showing the port at all in the address bar. Chrome usually shows the port, but omits it from error pages, because obviously if you fail to connect to a localhost URL the port is surely correct and you don't need to display it.

In Chrome, different localhost ports are treated as the same origin

That's not correct: the port is always part of the origin, even on localhost. You can verify this:

outer.html:
    <iframe src="http://localhost:8082/inner.html"></iframe>
inner.html:
    <script>window.parent.document.write("hello world");</script>

And then in two terminals:

$ python3 -m http.server 8081
$ python3 -m http.server 8082

If you visit http://localhost:8081/outer.html and open the console you'll see:

Uncaught DOMException: Blocked a frame with origin "http://localhost:8082" from accessing a cross-origin frame.

While if you visit http://localhost:8081/outer.html you'll see "hello world".

What's happening with zooming is that saved zoom settings are keyed by domain not origin: it always ignores the port, not just on localhost. See https://bugs.chromium.org/p/chromium/issues/detail?id=33311 and the issues that have been merged into it.

Chrome usually shows the port, but omits it from error pages

That's not what I'm seeing; I see the port included in the URL on error pages both on localhost and not.

Actually the bug linked described the intended behavior; the actual bug is https://bugs.chromium.org/p/chromium/issues/detail?id=967656&q=localhost%20zoom&can=1 which appears to have been incorrectly closed as a duplicate (of a bug which makes no mention of port numbers). Prior to ~2019 tabs on different localhost ports did not share zoom levels (I don't recall whether there was a shared zoom level per port, or if it just didn't share zoom levels between localhost tabs at all).

I think you're probably right about the CORS; I was inferring from the tab-zoom bug (which I did verify) to some speculations about other parts of origin handling (which I didn't verify).

When I go to localhost:1234 (a port number with nothing on it, the error page looks like this (note the localhost with no port number). (The port number is still in the address bar though.)