Closed Bug 903966 Opened 11 years ago Closed 7 years ago

Don't block mixed content from localhost IP addresses

Categories

(Core :: DOM: Security, enhancement, P3)

23 Branch
enhancement

Tracking

()

RESOLVED FIXED
mozilla55
Tracking Status
firefox55 --- fixed

People

(Reporter: mozillabugs, Assigned: poiru, NeedInfo)

References

(Blocks 1 open bug)

Details

(Keywords: dev-doc-complete, Whiteboard: [domsecurity-backlog])

Attachments

(1 file, 2 obsolete files)

Hi,
I upgraded to Firefox 23 and my application stopped working because of "Mixed Content Blocking".
My web application is served over https. It's doing an XHR request to POST http://localhost:12345/service to communicate with another process on the user's machine.

If I see it right, the goal of Mixed Content Blocking is to avoid MITM attacks. As MITM attacks aren't possible on localhost, could you please make an exception for it?
Since you control the application, you can try using JSONP or a form submit to get around these mixed content restrictions.
Marking this as an enhancement since what reproduces here is by design.

Joern, if you don't want to change the application, you can also set security.mixed_content.block_active_content as false in about:config. Of course, this affects all the content you load in the browser, not just the localhost stuff, so you will be decreasing security.
Severity: normal → enhancement
Component: General → Security
OS: Linux → All
Hardware: x86_64 → All
It would be a good idea that mixed content won't be blocked from localhost.
Status: UNCONFIRMED → NEW
Ever confirmed: true
It is quite irritating - for another example of situation where it is causing problems see https://github.com/openstreetmap/openstreetmap-website/issues/803
Firefox is extremely unlikely to allow this as long as the spec says not to and other browsers are behaving the same way. Firefox does allow an easy per-page override and a somewhat buried global override for the mixed-content blocker.
Component: Security → DOM: Security
Product: Firefox → Core
Whiteboard: Firefox is following the spec
(In reply to Daniel Veditz [:dveditz] from comment #6)
> Firefox is extremely unlikely to allow this as long as the spec says not to
> and other browsers are behaving the same way. Firefox does allow an easy
> per-page override and a somewhat buried global override for the
> mixed-content blocker.

Dan, it seems we are not going to allow that. Can we mark it as WONTFIX or do you want to keep the bug around?
Flags: needinfo?(dveditz)
Whiteboard: Firefox is following the spec → Firefox is following the spec, [domsecurity-backlog]
We can't WONTFIX it until we answer the following questions:

- What does IE do?

- What does Chrome do?

- Has WASWG formally agreed that it makes sense that a localhost URL is blockable mixed content[1] but is considered a secure context[2] if loaded as its own document? Or is this a "bug" in the specs?

[1] The MIXED spec says requests that are not "a priori authenticated" should be blocked. This is defined narrowly as having the schemes https or wss. If you made the request anyway the response must have its HTTPS state set to 'modern'. localhost loaded over plain HTTP would have an HTTPS state of 'none'.
https://w3c.github.io/webappsec-mixed-content/#should-block-fetch

[2] The SECURE CONTEXTS spec, on the other hand, explicitly includes localhost in its definition of "potentially trustworthy", which is defined as a superset of "a priori authenticated" so it's not a mere oversight that these definitions differ.
https://w3c.github.io/webappsec-secure-contexts/#is-origin-trustworthy

Note that my statements in other bugs that Tanvi references in comment 4 are objections to allowing sites to use localhost at all, securely or not, based on my belief that most such services are programmed with insufficient thought given to security and often installed on user's machines as part of other software without users being aware of the exposure. (This is much the kind of risk that led us to make most plugins "always ask" and could perhaps be given a similar treatment.) Those weren't arguments that the data was transferred insecurely, or that it should be blocked only some times (e.g. in the mixed case).
Flags: needinfo?(dveditz)
Priority: -- → P4
I think the spec has or will be updated soon to include localhost.
Priority: P4 → P3
Whiteboard: Firefox is following the spec, [domsecurity-backlog] → [domsecurity-backlog]
FWIW, Chrome 53 and later no longer trigger the mixed content blocker for http://127.0.0.1. See:
https://chromium.googlesource.com/chromium/src.git/+/130ee686fa00b617bfc001ceb3bb49782da2cb4e
Assignee: nobody → birunthan
Status: NEW → ASSIGNED
According to the spec, content from loopback addresses should no longer
be treated as mixed content even in secure origins. See:
- https://github.com/w3c/webappsec-mixed-content/commit/349501cdaa4b4dc1e2a8aacb216ced58fd316165
- https://w3c.github.io/webappsec-secure-contexts/#is-origin-trustworthy

Note that we only whitelist '127.0.0.1' and '::1' to match Chrome 53 and
later. See:
- https://chromium.googlesource.com/chromium/src.git/+/130ee686fa00b617bfc001ceb3bb49782da2cb4e

It is unclear if HTTPS origins should be able to use workers and WebSocket
connections through a loopback HTTP address. They are not supported in Chrome
(whether this is intentional or not is uncertain) so lets just ignore them for
now.

Tests for this are being reviewed at: https://github.com/w3c/web-platform-tests/pull/5304
Attachment #8853521 - Flags: review?(ckerschb)
Kate, Dan are you onboard with this change? Should we land that?
Flags: needinfo?(kmckinley)
Flags: needinfo?(dveditz)
I'm ok whitelisting literal 127.0.0.1 and ::1.  Doesn't look like there's a test for the IPv6 version; can our unit test framework handle those?
Flags: needinfo?(dveditz)
I think the change looks good, with one caveat.

https://bugzilla.mozilla.org/attachment.cgi?id=8853521&action=diff#a/dom/security/test/hsts/browser_hsts-priming_no-ip-address.js_sec2

The test server host value is used to generate a URI. Please change the test server host to 127.0.0.2 instead.
Flags: needinfo?(kmckinley)
Comment on attachment 8853521 [details] [diff] [review]
Stop blocking 'http://127.0.0.1/' as mixed content

Review of attachment 8853521 [details] [diff] [review]:
-----------------------------------------------------------------

Birunthan, can you address comment 14 and 15, then I am willing to accept the change. Thanks for providing the patch!
Attachment #8853521 - Flags: review?(ckerschb)
(In reply to Daniel Veditz [:dveditz] from comment #14)
> I'm ok whitelisting literal 127.0.0.1 and ::1.  Doesn't look like there's a
> test for the IPv6 version; can our unit test framework handle those?

httpd.js does not seem to work with IPv6. I tried to get it to work, but it's failing with HTTP 400 Bad Request. Unfortunately I don't have to time to look into it. Would you be OK landing this without a IPv6 test? Alternatively we could just remove support for the IPv6 loopback address.
Flags: needinfo?(dveditz)
We should be able to manually confirm that the IPv6 address works and then land without the test for it. Or maybe even better to include the test as a known failure until our infrastructure supports it. Surely we must use or want IPv6 in other network tests?
Flags: needinfo?(dveditz)
I found another way to test this for both IPv4 and IPv6.
Attachment #8853521 - Attachment is obsolete: true
Attachment #8865231 - Flags: review?(ckerschb)
Comment on attachment 8865231 [details] [diff] [review]
Stop blocking 'http://127.0.0.1/' as mixed content

Review of attachment 8865231 [details] [diff] [review]:
-----------------------------------------------------------------

Kate, I let you go first (since I want you to become a peer of dom:security). I'll have a final look once you r+ it.
Attachment #8865231 - Flags: review?(kmckinley)
Comment on attachment 8865231 [details] [diff] [review]
Stop blocking 'http://127.0.0.1/' as mixed content

Review of attachment 8865231 [details] [diff] [review]:
-----------------------------------------------------------------

Overall this looks good, please address the comments below.

::: browser/base/content/test/siteIdentity/test_no_mcb_for_loopback.html
@@ +1,1 @@
> +<!-- See browser_no_mcb_for_localhost.js -->

Please add images to this test. It would be good to have a test for cached images, as well. A good example might be to load an image over https:// and then add the image over http:// and check if the image loads.

@@ +37,5 @@
> +
> +  <script src="http://127.0.0.1:8/test.js"></script>
> +  <script src="http://[::1]:8/test.js"></script>
> +
> +  <link href="http://127.0.0.1:8/test.css" rel="stylesheet"></link>

Do we allow <link> elements to load in the body? MDN says otherwise.

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link
Attachment #8865231 - Flags: review?(kmckinley) → review+
Comment on attachment 8865231 [details] [diff] [review]
Stop blocking 'http://127.0.0.1/' as mixed content

Please address Kate's suggestions and I'll have a final look and we have that landed in no time. Thanks.
Attachment #8865231 - Flags: review?(ckerschb)
(In reply to Kate McKinley [:kmckinley] from comment #21)
> Please add images to this test. It would be good to have a test for cached
> images, as well. A good example might be to load an image over https:// and
> then add the image over http:// and check if the image loads.

Done. (I took a slightly different approach to test the cache.)

> @@ +37,5 @@
> > +
> > +  <script src="http://127.0.0.1:8/test.js"></script>
> > +  <script src="http://[::1]:8/test.js"></script>
> > +
> > +  <link href="http://127.0.0.1:8/test.css" rel="stylesheet"></link>
> 
> Do we allow <link> elements to load in the body? MDN says otherwise.

The <link> element wasn't in the <body>.
Attachment #8865231 - Attachment is obsolete: true
Attachment #8866324 - Flags: review?(ckerschb)
Comment on attachment 8866324 [details] [diff] [review]
Stop blocking 'http://127.0.0.1/' as mixed content

Review of attachment 8866324 [details] [diff] [review]:
-----------------------------------------------------------------

ship it - thanks!

::: browser/base/content/test/siteIdentity/browser_no_mcb_for_loopback.js
@@ +30,5 @@
> +    is(docShell.hasMixedDisplayContentBlocked, false, "hasMixedDisplayContentBlocked not set");
> +    is(docShell.hasMixedActiveContentBlocked, false, "hasMixedActiveContentBlocked not set");
> +  });
> +
> +  // Check that loopback content served from the cache is not blocked. 

nit: trailing whitespace

@@ +35,5 @@
> +  yield ContentTask.spawn(browser, null, function* () {
> +    const doc = content.document;
> +    const img = doc.createElement("img");
> +    const promiseImgLoaded = ContentTaskUtils.waitForEvent(img, "load", false);
> +    img.src = "http://127.0.0.1:8888/browser/browser/base/content/test/siteIdentity/moz.png";

can you define the src on top as a const, something like:
const URI = getRootDirectory(gTestPath).replace("chrome://mochitests/content", "http://127.0.0.1:8888") + "moz.png";
so in case the test gets moved it continues to work.
Attachment #8866324 - Flags: review?(ckerschb) → review+
Pushed by birunthan@mohanathas.com:
https://hg.mozilla.org/integration/mozilla-inbound/rev/74f065888725
Stop blocking 'http://127.0.0.1/' as mixed content. r=ckerschb,kmckinley
https://hg.mozilla.org/mozilla-central/rev/74f065888725
Status: ASSIGNED → RESOLVED
Closed: 7 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla55
Thanks so much for the patch. I've tested this with Nightly and it works great for GET requests. However I noticed that it doesn't work as expected for requests where the browser is supposed to issue a preflight OPTIONS request, for example if you want to issue a POST request and specify a Content-Type header. In this case the browser need to check the CORS header `Access-Control-Allow-Headers: Content-Type` via a preflight request first.

Examples to type into the developer console of a HTTPS site: (Tested with 55.0a1 (2017-05-11))

// (a) This works.
fetch('http://127.0.0.1:8060/', { method: 'POST', body: '["asdf"]' })
    .then(r => r.text()).then(r => console.log(r))

// (b) Fails with "TypeError: NetworkError when attempting to fetch resource."
fetch('http://127.0.0.1:8060/', { method: 'POST', body: '["asdf"]', headers: { 'Content-Type': 'application/json' } })
    .then(r => r.text()).then(r => console.log(r))

With Chrome it works as expected: (b) issues a preflight OPTIONS request followed by the POST. Not sure if I should open a new bug for this.
Flags: needinfo?(birunthan)
Flags: needinfo?(birunthan)
Keywords: dev-doc-needed
(In reply to Sebastian Volland from comment #27)
> Thanks so much for the patch. I've tested this with Nightly and it works
> great for GET requests. However I noticed that it doesn't work as expected
> for requests where the browser is supposed to issue a preflight OPTIONS
> request, for example if you want to issue a POST request and specify a
> Content-Type header. In this case the browser need to check the CORS header
> `Access-Control-Allow-Headers: Content-Type` via a preflight request first.

I'll investigate and post a follow-up patch either here or in a new bug. Thanks!
(In reply to Birunthan Mohanathas [:poiru] from comment #28)
 > I'll investigate and post a follow-up patch either here or in a new bug.
> Thanks!

Birunthan, thanks for following up on the issue. Please file a new bug and assign it to yourself which we can mark resolved if no follow up is needed in the end, but also makes sure the follow up is not slipping through the cracks. Thanks!
Flags: needinfo?(birunthan)
I have documented this by adding a note about the change to:
https://developer.mozilla.org/en-US/docs/Web/Security/Mixed_content

I've also added a note to the Fx55 release notes:
https://developer.mozilla.org/en-US/Firefox/Releases/55#Security

Let me know if you think any other mentions/changes are needed. Thanks!
Regression? Doesn't work on 56.0a1 (2017-06-16) (64-bit)

var x=new WebSocket('ws://127.0.0.1:3101') 
SecurityError: The operation is insecure.
(In reply to homakov from comment #32)
> Regression? Doesn't work on 56.0a1 (2017-06-16) (64-bit)
> 
> var x=new WebSocket('ws://127.0.0.1:3101') 
> SecurityError: The operation is insecure.

This should be a new bug. WebSocket have their own mechanism for determining if it is a mixed-content context.
(In reply to Christoph Kerschbaumer [:ckerschb] from comment #29)
> Birunthan, thanks for following up on the issue. Please file a new bug and
> assign it to yourself which we can mark resolved if no follow up is needed
> in the end, but also makes sure the follow up is not slipping through the
> cracks. Thanks!

Birunthan, I am going through my ni? queue at the moment. Is there anything we need to follow up or can you clear my ni?
Blocks: 1376309
Blocks: 1376310
I filed the follow-up bugs. Sorry for the delay!
Flags: needinfo?(birunthan)
If this is fixed, then why (on FF 60) does the following example fail from a HTTPS page (at the console):

r = new XMLHttpRequest(); 
r.open("POST","http://localhost:11080/__svc__",true); 
r.setRequestHeader("Content-Type","text/xml"); 
r.send("<r>xml</r>");

It fails with the following error:

Blocked loading mixed active content “http://localhost:11080/__svc__”[Learn More]

It never get's near our local application (running on port 11080).

Same failure on Windows and Mac OS/X.

Works on Chrome.
(In reply to Jason Lohrey from comment #37)

I meant also to say, that the fetch() command _does_ create a socket connection to the local application, so is not being blocked by FF.

E.g.:

fetch('http://127.0.0.1:11080/__svc__', { method: 'POST', body: '<r>xml</r>' }).then(r => r.text()).then(r => console.log(r))
Same problem,
It seems that mozilla has blocked localhost or 127.0.0.1 again on FF 60+. Why?

Here the example: Blocked loading mixed active content "http://localhost:49101/

Can you please return to allow http://localhost:xxx/xxxxx again?

Chrome and IE don't block the localhost!

Thank you in advance.
(In reply to Simone Granata from comment #39)
> Same problem,
> It seems that mozilla has blocked localhost or 127.0.0.1 again on FF 60+.
> Why?
> 
> Here the example: Blocked loading mixed active content
> "http://localhost:49101/
> 
> Can you please return to allow http://localhost:xxx/xxxxx again?
> 
> Chrome and IE don't block the localhost!
> 
> Thank you in advance.

I meant also to say, that I use jquery ajax request to call the REST API on localhost.
$.ajax({
 url: 'http://localhost:49101/version',
 type: 'GET',
 contentType: 'application/json',
 success: function(result) {
  $('#version').text(result.version);
 },
 error: function(error) {
  console.log(error);
 }
});
See Also: → 1488740
This Task seems to be resolved / fixed, but it isn't.
Firefox still does not allow to call http://localhost from a secured website.

Cheers
It appears that in version 62 even accessing https://127.0.0.1:12345/ no longer works from a secure site. This was working a month ago.

CORS is now blocking this request even when accessed from a secure site using a real SSL cert (not self signed). Works fine in Chrome, Edge, etc... 

Site is https://go.zspace.com which needs to talk to our service installed on our hardware.
Changing the summary to match the code that landed since it's confusing people (e.g. comment 42). Bug 1488740 covers adding the name "localhost" to this.
Summary: Don't block mixed content from localhost → Don't block mixed content from localhost IP addresses
(In reply to cbryant from comment #43)
> It appears that in version 62 even accessing https://127.0.0.1:12345/ no
> longer works from a secure site. This was working a month ago.
> 
> CORS is now blocking this request even when accessed from a secure site
> using a real SSL cert (not self signed). Works fine in Chrome, Edge, etc... 

CORS has nothing to do with mixed-content blocking or secure transport. If there's a difference between Firefox and Chrome with CORS behavior (whether limited to loopback or in general) please file a separate bug on it.
Flags: needinfo?(cbryant)

Firefox 84 and later allow loading of mixed content on http://localhost/ and http://*.localhost/ URLs, as these are now mapped to loopback addresses (see bug 1220810).
Please update the browser if you are still facing the issue.

You need to log in before you can comment on or make changes to this bug.