Bug 903966 - Stop blocking 'http://127.0.0.1/' as mixed content. r=ckerschb,kmckinley
According to the spec, content from loopback addresses should no longer be treated as mixed content even in secure origins. See: -349501cdaa- 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: -130ee686faIt 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. See also: https://github.com/w3c/web-platform-tests/pull/5304
This commit is contained in:
@@ -90,3 +90,8 @@ support-files =
|
||||
test_no_mcb_on_http_site_font.css
|
||||
test_no_mcb_on_http_site_font2.html
|
||||
test_no_mcb_on_http_site_font2.css
|
||||
[browser_no_mcb_for_loopback.js]
|
||||
tags = mcb
|
||||
support-files =
|
||||
../general/moz.png
|
||||
test_no_mcb_for_loopback.html
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// The test loads a HTTPS web page with active content from HTTP loopback URLs
|
||||
// and makes sure that the mixed content flags on the docshell are not set.
|
||||
//
|
||||
// Note that the URLs referenced within the test page intentionally use the
|
||||
// unassigned port 8 because we don't want to actually load anything, we just
|
||||
// want to check that the URLs are not blocked.
|
||||
|
||||
const TEST_URL = getRootDirectory(gTestPath).replace("chrome://mochitests/content", "https://example.com") + "test_no_mcb_for_loopback.html";
|
||||
|
||||
const LOOPBACK_PNG_URL = getRootDirectory(gTestPath).replace("chrome://mochitests/content", "http://127.0.0.1:8888") + "moz.png";
|
||||
|
||||
const PREF_BLOCK_DISPLAY = "security.mixed_content.block_display_content";
|
||||
const PREF_BLOCK_ACTIVE = "security.mixed_content.block_active_content";
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
Services.prefs.clearUserPref(PREF_BLOCK_DISPLAY);
|
||||
Services.prefs.clearUserPref(PREF_BLOCK_ACTIVE);
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
add_task(function* allowLoopbackMixedContent() {
|
||||
Services.prefs.setBoolPref(PREF_BLOCK_DISPLAY, true);
|
||||
Services.prefs.setBoolPref(PREF_BLOCK_ACTIVE, true);
|
||||
|
||||
const tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
|
||||
const browser = gBrowser.getBrowserForTab(tab);
|
||||
|
||||
yield ContentTask.spawn(browser, null, function() {
|
||||
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.
|
||||
yield ContentTask.spawn(browser, LOOPBACK_PNG_URL, function* (loopbackPNGUrl) {
|
||||
const doc = content.document;
|
||||
const img = doc.createElement("img");
|
||||
const promiseImgLoaded = ContentTaskUtils.waitForEvent(img, "load", false);
|
||||
img.src = loopbackPNGUrl;
|
||||
Assert.ok(!img.complete, "loopback image not yet loaded");
|
||||
doc.body.appendChild(img);
|
||||
yield promiseImgLoaded;
|
||||
|
||||
const cachedImg = doc.createElement("img");
|
||||
cachedImg.src = img.src;
|
||||
Assert.ok(cachedImg.complete, "loopback image loaded from cache");
|
||||
});
|
||||
|
||||
assertMixedContentBlockingState(browser, {
|
||||
activeBlocked: false,
|
||||
activeLoaded: false,
|
||||
passiveLoaded: false,
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,50 @@
|
||||
<!-- See browser_no_mcb_for_localhost.js -->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
<title>Bug 903966</title>
|
||||
</head>
|
||||
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: "Font-IPv4";
|
||||
src: url("http://127.0.0.1:8/test.ttf");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Font-IPv6";
|
||||
src: url("http://[::1]:8/test.ttf");
|
||||
}
|
||||
|
||||
#ip-v4 {
|
||||
font-family: "Font-IPv4"
|
||||
}
|
||||
|
||||
#ip-v6 {
|
||||
font-family: "Font-IPv6"
|
||||
}
|
||||
</style>
|
||||
|
||||
<body>
|
||||
<div id="ip-v4">test</div>
|
||||
<div id="ip-v6">test</div>
|
||||
|
||||
<img src="http://127.0.0.1:8/test.png">
|
||||
<img src="http://[::1]:8/test.png">
|
||||
|
||||
<iframe src="http://127.0.0.1:8/test.html"></iframe>
|
||||
<iframe src="http://[::1]:8/test.html"></iframe>
|
||||
</body>
|
||||
|
||||
<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>
|
||||
<link href="http://[::1]:8/test.css" rel="stylesheet"></link>
|
||||
|
||||
<script>
|
||||
fetch("http://127.0.0.1:8");
|
||||
fetch("http://[::1]:8");
|
||||
</script>
|
||||
</html>
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "mozilla/dom/AutocompleteErrorEvent.h"
|
||||
#include "mozilla/dom/nsCSPUtils.h"
|
||||
#include "mozilla/dom/nsCSPContext.h"
|
||||
#include "mozilla/dom/nsMixedContentBlocker.h"
|
||||
#include "mozilla/dom/HTMLFormControlsCollection.h"
|
||||
#include "mozilla/dom/HTMLFormElementBinding.h"
|
||||
#include "mozilla/Move.h"
|
||||
@@ -907,6 +908,10 @@ HTMLFormElement::DoSecureToInsecureSubmitCheck(nsIURI* aActionURL,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (nsMixedContentBlocker::IsPotentiallyTrustworthyLoopbackURL(aActionURL)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowOuter> window = OwnerDoc()->GetWindow();
|
||||
if (!window) {
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
@@ -235,7 +235,8 @@ LOCAL_INCLUDES += [
|
||||
'/dom/base',
|
||||
'/dom/canvas',
|
||||
'/dom/html/input',
|
||||
'/dom/media/',
|
||||
'/dom/media',
|
||||
'/dom/security',
|
||||
'/dom/xbl',
|
||||
'/dom/xul',
|
||||
'/editor/txmgr',
|
||||
|
||||
@@ -427,6 +427,18 @@ nsMixedContentBlocker::ShouldLoad(uint32_t aContentType,
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool
|
||||
nsMixedContentBlocker::IsPotentiallyTrustworthyLoopbackURL(nsIURI* aURL) {
|
||||
nsAutoCString host;
|
||||
nsresult rv = aURL->GetHost(host);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
// We could also allow 'localhost' (if we can guarantee that it resolves
|
||||
// to a loopback address), but Chrome doesn't support it as of writing. For
|
||||
// web compat, lets only allow what Chrome allows.
|
||||
return host.Equals("127.0.0.1") || host.Equals("::1");
|
||||
}
|
||||
|
||||
/* Static version of ShouldLoad() that contains all the Mixed Content Blocker
|
||||
* logic. Called from non-static ShouldLoad().
|
||||
*/
|
||||
@@ -729,6 +741,18 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool isHttpScheme = false;
|
||||
rv = innerContentLocation->SchemeIs("http", &isHttpScheme);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Loopback origins are not considered mixed content even over HTTP. See:
|
||||
// https://w3c.github.io/webappsec-mixed-content/#should-block-fetch
|
||||
if (isHttpScheme &&
|
||||
IsPotentiallyTrustworthyLoopbackURL(innerContentLocation)) {
|
||||
*aDecision = ACCEPT;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// The page might have set the CSP directive 'upgrade-insecure-requests'. In such
|
||||
// a case allow the http: load to succeed with the promise that the channel will
|
||||
// get upgraded to https before fetching any data from the netwerk.
|
||||
@@ -740,9 +764,6 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
|
||||
// we only have to check against http: here. Skip mixed content blocking if the
|
||||
// subresource load uses http: and the CSP directive 'upgrade-insecure-requests'
|
||||
// is present on the page.
|
||||
bool isHttpScheme = false;
|
||||
rv = innerContentLocation->SchemeIs("http", &isHttpScheme);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsIDocument* document = docShell->GetDocument();
|
||||
MOZ_ASSERT(document, "Expected a document");
|
||||
if (isHttpScheme && document->GetUpgradeInsecureRequests(isPreload)) {
|
||||
|
||||
@@ -45,6 +45,10 @@ public:
|
||||
|
||||
nsMixedContentBlocker();
|
||||
|
||||
// See:
|
||||
// https://w3c.github.io/webappsec-secure-contexts/#is-origin-trustworthy
|
||||
static bool IsPotentiallyTrustworthyLoopbackURL(nsIURI* aURL);
|
||||
|
||||
/* Static version of ShouldLoad() that contains all the Mixed Content Blocker
|
||||
* logic. Called from non-static ShouldLoad().
|
||||
* Called directly from imageLib when an insecure redirect exists in a cached
|
||||
|
||||
@@ -14,7 +14,7 @@ add_task(function*() {
|
||||
|
||||
// add the top-level server
|
||||
test_servers['localhost-ip'] = {
|
||||
host: '127.0.0.1',
|
||||
host: '127.0.0.2',
|
||||
response: true,
|
||||
id: 'localhost-ip',
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user