mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-04 23:08:39 +09:00
moebius#223: Consider blocking top level window data: URIs (part 1/3 without tests)
https://github.com/MoonchildProductions/moebius/pull/223
This commit is contained in:
parent
08e2f9aaea
commit
712d19e1b7
22 changed files with 515 additions and 1 deletions
|
|
@ -42,6 +42,7 @@
|
|||
|
||||
#include "nsArray.h"
|
||||
#include "nsArrayUtils.h"
|
||||
#include "nsContentSecurityManager.h"
|
||||
#include "nsICaptivePortalService.h"
|
||||
#include "nsIDOMStorage.h"
|
||||
#include "nsIContentViewer.h"
|
||||
|
|
@ -9884,6 +9885,15 @@ nsDocShell::InternalLoad(nsIURI* aURI,
|
|||
contentType = nsIContentPolicy::TYPE_DOCUMENT;
|
||||
}
|
||||
|
||||
if (!nsContentSecurityManager::AllowTopLevelNavigationToDataURI(
|
||||
aURI,
|
||||
contentType,
|
||||
aTriggeringPrincipal,
|
||||
(aLoadType == LOAD_NORMAL_EXTERNAL))) {
|
||||
// logging to console happens within AllowTopLevelNavigationToDataURI
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// If there's no targetDocShell, that means we are about to create a new window,
|
||||
// perform a content policy check before creating the window.
|
||||
if (!targetDocShell) {
|
||||
|
|
@ -10232,8 +10242,11 @@ nsDocShell::InternalLoad(nsIURI* aURI,
|
|||
}
|
||||
}
|
||||
|
||||
bool loadFromExternal = false;
|
||||
|
||||
// Before going any further vet loads initiated by external programs.
|
||||
if (aLoadType == LOAD_NORMAL_EXTERNAL) {
|
||||
loadFromExternal = true;
|
||||
// Disallow external chrome: loads targetted at content windows
|
||||
bool isChrome = false;
|
||||
if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)) && isChrome) {
|
||||
|
|
@ -10724,7 +10737,7 @@ nsDocShell::InternalLoad(nsIURI* aURI,
|
|||
nsINetworkPredictor::PREDICT_LOAD, this, nullptr);
|
||||
|
||||
nsCOMPtr<nsIRequest> req;
|
||||
rv = DoURILoad(aURI, aOriginalURI, aLoadReplace, aReferrer,
|
||||
rv = DoURILoad(aURI, aOriginalURI, aLoadReplace, loadFromExternal, aReferrer,
|
||||
!(aFlags & INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER),
|
||||
aReferrerPolicy,
|
||||
aTriggeringPrincipal, principalToInherit, aTypeHint,
|
||||
|
|
@ -10804,6 +10817,7 @@ nsresult
|
|||
nsDocShell::DoURILoad(nsIURI* aURI,
|
||||
nsIURI* aOriginalURI,
|
||||
bool aLoadReplace,
|
||||
bool aLoadFromExternal,
|
||||
nsIURI* aReferrerURI,
|
||||
bool aSendReferrer,
|
||||
uint32_t aReferrerPolicy,
|
||||
|
|
|
|||
|
|
@ -369,6 +369,7 @@ protected:
|
|||
nsresult DoURILoad(nsIURI* aURI,
|
||||
nsIURI* aOriginalURI,
|
||||
bool aLoadReplace,
|
||||
bool aLoadFromExternal,
|
||||
nsIURI* aReferrer,
|
||||
bool aSendReferrer,
|
||||
uint32_t aReferrerPolicy,
|
||||
|
|
|
|||
|
|
@ -81,3 +81,6 @@ MimeTypeMismatch=The resource from “%1$S” was blocked due to MIME type misma
|
|||
XCTOHeaderValueMissing=X-Content-Type-Options header warning: value was “%1$S”; did you mean to send “nosniff”?
|
||||
|
||||
BlockScriptWithWrongMimeType=Script from “%1$S” was blocked because of a disallowed MIME type.
|
||||
|
||||
# LOCALIZATION NOTE: Do not translate "data: URI".
|
||||
BlockTopLevelDataURINavigation=Navigation to toplevel data: URI not allowed (Blocked loading of: “%1$S”)
|
||||
|
|
|
|||
|
|
@ -1,13 +1,16 @@
|
|||
#include "nsContentSecurityManager.h"
|
||||
#include "nsEscape.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsIHttpChannelInternal.h"
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsILoadInfo.h"
|
||||
#include "nsIOService.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCORSListenerProxy.h"
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsMixedContentBlocker.h"
|
||||
#include "nsNullPrincipal.h"
|
||||
|
||||
#include "mozilla/dom/Element.h"
|
||||
|
||||
|
|
@ -15,6 +18,66 @@ NS_IMPL_ISUPPORTS(nsContentSecurityManager,
|
|||
nsIContentSecurityManager,
|
||||
nsIChannelEventSink)
|
||||
|
||||
/* static */ bool
|
||||
nsContentSecurityManager::AllowTopLevelNavigationToDataURI(
|
||||
nsIURI* aURI,
|
||||
nsContentPolicyType aContentPolicyType,
|
||||
nsIPrincipal* aTriggeringPrincipal,
|
||||
bool aLoadFromExternal)
|
||||
{
|
||||
// Let's block all toplevel document navigations to a data: URI.
|
||||
// In all cases where the toplevel document is navigated to a
|
||||
// data: URI the triggeringPrincipal is a codeBasePrincipal, or
|
||||
// a NullPrincipal. In other cases, e.g. typing a data: URL into
|
||||
// the URL-Bar, the triggeringPrincipal is a SystemPrincipal;
|
||||
// we don't want to block those loads. Only exception, loads coming
|
||||
// from an external applicaton (e.g. Thunderbird) don't load
|
||||
// using a codeBasePrincipal, but we want to block those loads.
|
||||
if (!mozilla::net::nsIOService::BlockToplevelDataUriNavigations()) {
|
||||
return true;
|
||||
}
|
||||
if (aContentPolicyType != nsIContentPolicy::TYPE_DOCUMENT) {
|
||||
return true;
|
||||
}
|
||||
bool isDataURI =
|
||||
(NS_SUCCEEDED(aURI->SchemeIs("data", &isDataURI)) && isDataURI);
|
||||
if (!isDataURI) {
|
||||
return true;
|
||||
}
|
||||
// Whitelist data: images as long as they are not SVGs
|
||||
nsAutoCString filePath;
|
||||
aURI->GetFilePath(filePath);
|
||||
if (StringBeginsWith(filePath, NS_LITERAL_CSTRING("image/")) &&
|
||||
!StringBeginsWith(filePath, NS_LITERAL_CSTRING("image/svg+xml"))) {
|
||||
return true;
|
||||
}
|
||||
// Whitelist data: PDFs and JSON
|
||||
if (StringBeginsWith(filePath, NS_LITERAL_CSTRING("application/pdf")) ||
|
||||
StringBeginsWith(filePath, NS_LITERAL_CSTRING("application/json"))) {
|
||||
return true;
|
||||
}
|
||||
if (!aLoadFromExternal &&
|
||||
nsContentUtils::IsSystemPrincipal(aTriggeringPrincipal)) {
|
||||
return true;
|
||||
}
|
||||
nsAutoCString dataSpec;
|
||||
aURI->GetSpec(dataSpec);
|
||||
if (dataSpec.Length() > 50) {
|
||||
dataSpec.Truncate(50);
|
||||
dataSpec.AppendLiteral("...");
|
||||
}
|
||||
NS_ConvertUTF8toUTF16 specUTF16(NS_UnescapeURL(dataSpec));
|
||||
const char16_t* params[] = { specUTF16.get() };
|
||||
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
|
||||
NS_LITERAL_CSTRING("DATA_URI_BLOCKED"),
|
||||
// no doc available, log to browser console
|
||||
nullptr,
|
||||
nsContentUtils::eSECURITY_PROPERTIES,
|
||||
"BlockTopLevelDataURINavigation",
|
||||
params, ArrayLength(params));
|
||||
return false;
|
||||
}
|
||||
|
||||
static nsresult
|
||||
ValidateSecurityFlags(nsILoadInfo* aLoadInfo)
|
||||
{
|
||||
|
|
@ -478,6 +541,27 @@ nsContentSecurityManager::AsyncOnChannelRedirect(nsIChannel* aOldChannel,
|
|||
}
|
||||
}
|
||||
|
||||
// Redirecting to a toplevel data: URI is not allowed, hence we pass
|
||||
// a NullPrincipal as the TriggeringPrincipal to
|
||||
// AllowTopLevelNavigationToDataURI() which definitely blocks any
|
||||
// data: URI load.
|
||||
nsCOMPtr<nsILoadInfo> newLoadInfo = aNewChannel->GetLoadInfo();
|
||||
if (newLoadInfo) {
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsresult rv = NS_GetFinalChannelURI(aNewChannel, getter_AddRefs(uri));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIPrincipal> nullTriggeringPrincipal = nsNullPrincipal::Create();
|
||||
if (!nsContentSecurityManager::AllowTopLevelNavigationToDataURI(
|
||||
uri,
|
||||
newLoadInfo->GetExternalContentPolicyType(),
|
||||
nullTriggeringPrincipal,
|
||||
false)) {
|
||||
// logging to console happens within AllowTopLevelNavigationToDataURI
|
||||
aOldChannel->Cancel(NS_ERROR_DOM_BAD_URI);
|
||||
return NS_ERROR_DOM_BAD_URI;
|
||||
}
|
||||
}
|
||||
|
||||
// Also verify that the redirecting server is allowed to redirect to the
|
||||
// given URI
|
||||
nsCOMPtr<nsIPrincipal> oldPrincipal;
|
||||
|
|
|
|||
|
|
@ -32,6 +32,11 @@ public:
|
|||
static nsresult doContentSecurityCheck(nsIChannel* aChannel,
|
||||
nsCOMPtr<nsIStreamListener>& aInAndOutListener);
|
||||
|
||||
static bool AllowTopLevelNavigationToDataURI(nsIURI* aURI,
|
||||
nsContentPolicyType aContentPolicyType,
|
||||
nsIPrincipal* aTriggeringPrincipal,
|
||||
bool aLoadFromExternal);
|
||||
|
||||
private:
|
||||
static nsresult CheckChannel(nsIChannel* aChannel);
|
||||
|
||||
|
|
|
|||
5
dom/security/test/general/browser.ini
Normal file
5
dom/security/test/general/browser.ini
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
[DEFAULT]
|
||||
[browser_test_toplevel_data_navigations.js]
|
||||
support-files =
|
||||
file_toplevel_data_navigations.sjs
|
||||
file_toplevel_data_meta_redirect.html
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
/* eslint-disable mozilla/no-arbitrary-setTimeout */
|
||||
|
||||
"use strict";
|
||||
|
||||
const kDataBody = "toplevel navigation to data: URI allowed";
|
||||
const kDataURI = "data:text/html,<body>" + kDataBody + "</body>";
|
||||
const kTestPath = getRootDirectory(gTestPath)
|
||||
.replace("chrome://mochitests/content", "http://example.com")
|
||||
const kRedirectURI = kTestPath + "file_toplevel_data_navigations.sjs";
|
||||
const kMetaRedirectURI = kTestPath + "file_toplevel_data_meta_redirect.html";
|
||||
|
||||
add_task(async function test_nav_data_uri() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
"set": [["security.data_uri.block_toplevel_data_uri_navigations", true]],
|
||||
});
|
||||
await BrowserTestUtils.withNewTab(kDataURI, async function(browser) {
|
||||
await ContentTask.spawn(gBrowser.selectedBrowser, {kDataBody}, async function({kDataBody}) { // eslint-disable-line
|
||||
is(content.document.body.innerHTML, kDataBody,
|
||||
"data: URI navigation from system should be allowed");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_nav_data_uri_redirect() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
"set": [["security.data_uri.block_toplevel_data_uri_navigations", true]],
|
||||
});
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, kRedirectURI);
|
||||
registerCleanupFunction(async function() {
|
||||
await BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
// wait to make sure data: URI did not load before checking that it got blocked
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
await ContentTask.spawn(gBrowser.selectedBrowser, {}, async function() {
|
||||
is(content.document.body.innerHTML, "",
|
||||
"data: URI navigation after server redirect should be blocked");
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_nav_data_uri_meta_redirect() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
"set": [["security.data_uri.block_toplevel_data_uri_navigations", true]],
|
||||
});
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, kMetaRedirectURI);
|
||||
registerCleanupFunction(async function() {
|
||||
await BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
// wait to make sure data: URI did not load before checking that it got blocked
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
await ContentTask.spawn(gBrowser.selectedBrowser, {}, async function() {
|
||||
is(content.document.body.innerHTML, "",
|
||||
"data: URI navigation after meta redirect should be blocked");
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Toplevel data navigation</title>
|
||||
</head>
|
||||
<body>
|
||||
test1: clicking data: URI tries to navigate window<br/>
|
||||
<a id="testlink" href="data:text/html,<body>toplevel data: URI navigations should be blocked</body>">click me</a>
|
||||
<script>
|
||||
document.getElementById('testlink').click();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Toplevel data navigation</title>
|
||||
</head>
|
||||
<body>
|
||||
test2: data: URI in iframe tries to window.open(data:, _blank);<br/>
|
||||
<iframe id="testFrame" src=""></iframe>
|
||||
<script>
|
||||
let DATA_URI = `data:text/html,<body><script>
|
||||
var win = window.open("data:text/html,<body>toplevel data: URI navigations should be blocked</body>", "_blank");
|
||||
setTimeout(function () {
|
||||
var result = win.document.body.innerHTML === "" ? "blocked" : "navigated";
|
||||
parent.postMessage(result, "*");
|
||||
win.close();
|
||||
}, 1000);
|
||||
<\/script></body>`;
|
||||
|
||||
window.addEventListener("message", receiveMessage);
|
||||
function receiveMessage(event) {
|
||||
window.removeEventListener("message", receiveMessage);
|
||||
// propagate the information back to the caller
|
||||
window.opener.postMessage(event.data, "*");
|
||||
}
|
||||
document.getElementById('testFrame').src = DATA_URI;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Toplevel data navigation</title>
|
||||
</head>
|
||||
<body>
|
||||
test3: performing data: URI navigation through win.loc.href<br/>
|
||||
<script>
|
||||
window.location.href = "data:text/html,<body>toplevel data: URI navigations should be blocked</body>";
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
// Custom *.sjs file specifically for the needs of Bug:
|
||||
// Bug 1394554 - Block toplevel data: URI navigations after redirect
|
||||
|
||||
var DATA_URI =
|
||||
"<body>toplevel data: URI navigations after redirect should be blocked</body>";
|
||||
|
||||
function handleRequest(request, response)
|
||||
{
|
||||
// avoid confusing cache behaviors
|
||||
response.setHeader("Cache-Control", "no-cache", false);
|
||||
|
||||
response.setStatusLine("1.1", 302, "Found");
|
||||
response.setHeader("Location", "data:text/html," + escape(DATA_URI), false);
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<html>
|
||||
<body>
|
||||
<head>
|
||||
<meta http-equiv="refresh"
|
||||
content="0; url='data:text/html,<body>toplevel meta redirect to data: URI should be blocked</body>'">
|
||||
</head>
|
||||
<body>
|
||||
Meta Redirect to data: URI
|
||||
</body>
|
||||
</html>
|
||||
14
dom/security/test/general/file_toplevel_data_navigations.sjs
Normal file
14
dom/security/test/general/file_toplevel_data_navigations.sjs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
// Custom *.sjs file specifically for the needs of Bug:
|
||||
// Bug 1394554 - Block toplevel data: URI navigations after redirect
|
||||
|
||||
var DATA_URI =
|
||||
"data:text/html,<body>toplevel data: URI navigations after redirect should be blocked</body>";
|
||||
|
||||
function handleRequest(request, response)
|
||||
{
|
||||
// avoid confusing cache behaviors
|
||||
response.setHeader("Cache-Control", "no-cache", false);
|
||||
|
||||
response.setStatusLine("1.1", 302, "Found");
|
||||
response.setHeader("Location", DATA_URI, false);
|
||||
}
|
||||
|
|
@ -3,7 +3,19 @@ support-files =
|
|||
file_contentpolicytype_targeted_link_iframe.sjs
|
||||
file_nosniff_testserver.sjs
|
||||
file_block_script_wrong_mime_server.sjs
|
||||
file_block_toplevel_data_navigation.html
|
||||
file_block_toplevel_data_navigation2.html
|
||||
file_block_toplevel_data_navigation3.html
|
||||
file_block_toplevel_data_redirect.sjs
|
||||
|
||||
[test_contentpolicytype_targeted_link_iframe.html]
|
||||
[test_nosniff.html]
|
||||
[test_block_script_wrong_mime.html]
|
||||
[test_block_toplevel_data_navigation.html]
|
||||
skip-if = toolkit == 'android' # intermittent failure
|
||||
[test_block_toplevel_data_img_navigation.html]
|
||||
skip-if = toolkit == 'android' # intermittent failure
|
||||
[test_allow_opening_data_pdf.html]
|
||||
skip-if = toolkit == 'android'
|
||||
[test_allow_opening_data_json.html]
|
||||
skip-if = toolkit == 'android'
|
||||
|
|
|
|||
39
dom/security/test/general/test_allow_opening_data_json.html
Normal file
39
dom/security/test/general/test_allow_opening_data_json.html
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Bug 1403814: Allow toplevel data URI navigation data:application/json</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function test_toplevel_data_json() {
|
||||
const DATA_JSON = "data:application/json,{'my_json_key':'my_json_value'}";
|
||||
|
||||
let win = window.open(DATA_JSON);
|
||||
let wrappedWin = SpecialPowers.wrap(win);
|
||||
|
||||
// Unfortunately we can't detect whether the JSON has loaded or not using some
|
||||
// event, hence we are constantly polling location.href till we see that
|
||||
// the data: URI appears. Test times out on failure.
|
||||
var jsonLoaded = setInterval(function() {
|
||||
if (wrappedWin.document.location.href.startsWith("data:application/json")) {
|
||||
clearInterval(jsonLoaded);
|
||||
ok(true, "navigating to data:application/json allowed");
|
||||
wrappedWin.close();
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}, 200);
|
||||
}
|
||||
|
||||
SpecialPowers.pushPrefEnv({
|
||||
set: [["security.data_uri.block_toplevel_data_uri_navigations", true]]
|
||||
}, test_toplevel_data_json);
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
41
dom/security/test/general/test_allow_opening_data_pdf.html
Normal file
41
dom/security/test/general/test_allow_opening_data_pdf.html
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Bug 1398692: Allow toplevel navigation to a data:application/pdf</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function test_toplevel_data_pdf() {
|
||||
// The PDF contains one page and it is a 3/72" square, the minimum allowed by the spec
|
||||
const DATA_PDF =
|
||||
"data:application/pdf;base64,JVBERi0xLjANCjEgMCBvYmo8PC9UeXBlL0NhdGFsb2cvUGFnZXMgMiAwIFI+PmVuZG9iaiAyIDAgb2JqPDwvVHlwZS9QYWdlcy9LaWRzWzMgMCBSXS9Db3VudCAxPj5lbmRvYmogMyAwIG9iajw8L1R5cGUvUGFnZS9NZWRpYUJveFswIDAgMyAzXT4+ZW5kb2JqDQp4cmVmDQowIDQNCjAwMDAwMDAwMDAgNjU1MzUgZg0KMDAwMDAwMDAxMCAwMDAwMCBuDQowMDAwMDAwMDUzIDAwMDAwIG4NCjAwMDAwMDAxMDIgMDAwMDAgbg0KdHJhaWxlcjw8L1NpemUgNC9Sb290IDEgMCBSPj4NCnN0YXJ0eHJlZg0KMTQ5DQolRU9G";
|
||||
|
||||
let win = window.open(DATA_PDF);
|
||||
let wrappedWin = SpecialPowers.wrap(win);
|
||||
|
||||
// Unfortunately we can't detect whether the PDF has loaded or not using some
|
||||
// event, hence we are constantly polling location.href till we see that
|
||||
// the data: URI appears. Test times out on failure.
|
||||
var pdfLoaded = setInterval(function() {
|
||||
if (wrappedWin.document.location.href.startsWith("data:application/pdf")) {
|
||||
clearInterval(pdfLoaded);
|
||||
ok(true, "navigating to data:application/pdf allowed");
|
||||
wrappedWin.close();
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}, 200);
|
||||
}
|
||||
|
||||
SpecialPowers.pushPrefEnv({
|
||||
set: [["security.data_uri.block_toplevel_data_uri_navigations", true]]
|
||||
}, test_toplevel_data_pdf);
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Bug 1396798: Do not block toplevel data: navigation to image (except svgs)</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<script class="testbody" type="text/javascript">
|
||||
SpecialPowers.setBoolPref("security.data_uri.block_toplevel_data_uri_navigations", true);
|
||||
SimpleTest.registerCleanupFunction(() => {
|
||||
SpecialPowers.clearUserPref("security.data_uri.block_toplevel_data_uri_navigations");
|
||||
});
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.requestFlakyTimeout("have to test that top level data:image loading is blocked/allowed");
|
||||
|
||||
function test_toplevel_data_image() {
|
||||
const DATA_PNG =
|
||||
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==";
|
||||
let win1 = window.open(DATA_PNG);
|
||||
let wrappedWin1 = SpecialPowers.wrap(win1);
|
||||
setTimeout(function () {
|
||||
let images = wrappedWin1.document.getElementsByTagName('img');
|
||||
is(images.length, 1, "Loading data:image/png should be allowed");
|
||||
is(images[0].src, DATA_PNG, "Sanity: img src matches");
|
||||
wrappedWin1.close();
|
||||
test_toplevel_data_image_svg();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function test_toplevel_data_image_svg() {
|
||||
const DATA_SVG =
|
||||
"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDE2IDE2Ij4KICA8cGF0aCBkPSJNOCwxMkwzLDcsNCw2bDQsNCw0LTQsMSwxWiIgZmlsbD0iIzZBNkE2QSIgLz4KPC9zdmc+Cg==";
|
||||
let win2 = window.open(DATA_SVG);
|
||||
let wrappedWin2 = SpecialPowers.wrap(win2);
|
||||
setTimeout(function () {
|
||||
isnot(wrappedWin2.document.documentElement.localName, "svg",
|
||||
"Loading data:image/svg+xml should be blocked");
|
||||
wrappedWin2.close();
|
||||
SimpleTest.finish();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
// fire up the tests
|
||||
test_toplevel_data_image();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Bug 1331351 - Block top level window data: URI navigations</title>
|
||||
<!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<script class="testbody" type="text/javascript">
|
||||
SpecialPowers.setBoolPref("security.data_uri.block_toplevel_data_uri_navigations", true);
|
||||
SimpleTest.registerCleanupFunction(() => {
|
||||
SpecialPowers.clearUserPref("security.data_uri.block_toplevel_data_uri_navigations");
|
||||
});
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.requestFlakyTimeout("have to test that top level data: URI navgiation is blocked");
|
||||
|
||||
function test1() {
|
||||
// simple data: URI click navigation should be prevented
|
||||
let TEST_FILE = "file_block_toplevel_data_navigation.html";
|
||||
let win1 = window.open(TEST_FILE);
|
||||
var readyStateCheckInterval = setInterval(function() {
|
||||
let state = win1.document.readyState;
|
||||
if (state === "interactive" || state === "complete") {
|
||||
clearInterval(readyStateCheckInterval);
|
||||
ok(win1.document.body.innerHTML.indexOf("test1:") !== -1,
|
||||
"toplevel data: URI navigation through click() should be blocked");
|
||||
win1.close();
|
||||
test2();
|
||||
}
|
||||
}, 200);
|
||||
}
|
||||
|
||||
function test2() {
|
||||
// data: URI in iframe which opens data: URI in _blank should be blocked
|
||||
let win2 = window.open("file_block_toplevel_data_navigation2.html");
|
||||
window.addEventListener("message", receiveMessage);
|
||||
function receiveMessage(event) {
|
||||
window.removeEventListener("message", receiveMessage);
|
||||
is(event.data, "blocked",
|
||||
"data: URI navigation using _blank from data: URI should be blocked");
|
||||
win2.close();
|
||||
test3();
|
||||
}
|
||||
}
|
||||
|
||||
function test3() {
|
||||
// navigating to a data: URI using window.location.href should be blocked
|
||||
let win3 = window.open("file_block_toplevel_data_navigation3.html");
|
||||
setTimeout(function () {
|
||||
ok(win3.document.body.innerHTML.indexOf("test3:") !== -1,
|
||||
"data: URI navigation through win.loc.href should be blocked");
|
||||
win3.close();
|
||||
test4();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function test4() {
|
||||
// navigating to a data: URI using window.open() should be blocked
|
||||
let win4 = window.open("data:text/html,<body>toplevel data: URI navigations should be blocked</body>");
|
||||
setTimeout(function () {
|
||||
// Please note that the data: URI will be displayed in the URL-Bar but not
|
||||
// loaded, hence we rather rely on document.body than document.location
|
||||
is(win4.document.body.innerHTML, "",
|
||||
"navigating to a data: URI using window.open() should be blocked");
|
||||
test5();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function test5() {
|
||||
// navigating to a URI which redirects to a data: URI using window.open() should be blocked
|
||||
let win5 = window.open("file_block_toplevel_data_redirect.sjs");
|
||||
setTimeout(function () {
|
||||
// Please note that the data: URI will be displayed in the URL-Bar but not
|
||||
// loaded, hence we rather rely on document.body than document.location
|
||||
is(SpecialPowers.wrap(win5).document.body.innerHTML, "",
|
||||
"navigating to URI which redirects to a data: URI using window.open() should be blocked");
|
||||
win5.close();
|
||||
SimpleTest.finish();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
// fire up the tests
|
||||
test1();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -27,5 +27,6 @@ MOCHITEST_CHROME_MANIFESTS += [
|
|||
BROWSER_CHROME_MANIFESTS += [
|
||||
'contentverifier/browser.ini',
|
||||
'csp/browser.ini',
|
||||
'general/browser.ini',
|
||||
'hsts/browser.ini',
|
||||
]
|
||||
|
|
|
|||
|
|
@ -5572,6 +5572,12 @@ pref("security.mixed_content.use_hsts", true);
|
|||
// Approximately 1 week default cache for HSTS priming failures
|
||||
pref ("security.mixed_content.hsts_priming_cache_timeout", 10080);
|
||||
|
||||
// TODO: Bug 1380959: Block toplevel data: URI navigations
|
||||
// If true, all toplevel data: URI navigations will be blocked.
|
||||
// Please note that manually entering a data: URI in the
|
||||
// URL-Bar will not be blocked when flipping this pref.
|
||||
pref("security.data_uri.block_toplevel_data_uri_navigations", false);
|
||||
|
||||
// Disable Storage api in release builds.
|
||||
#ifdef NIGHTLY_BUILD
|
||||
pref("dom.storageManager.enabled", true);
|
||||
|
|
|
|||
|
|
@ -173,6 +173,8 @@ uint32_t nsIOService::gDefaultSegmentCount = 24;
|
|||
|
||||
bool nsIOService::sTelemetryEnabled = false;
|
||||
|
||||
bool nsIOService::sBlockToplevelDataUriNavigations = false;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
nsIOService::nsIOService()
|
||||
|
|
@ -251,6 +253,8 @@ nsIOService::Init()
|
|||
NS_WARNING("failed to get observer service");
|
||||
|
||||
Preferences::AddBoolVarCache(&sTelemetryEnabled, "toolkit.telemetry.enabled", false);
|
||||
Preferences::AddBoolVarCache(&sBlockToplevelDataUriNavigations,
|
||||
"security.data_uri.block_toplevel_data_uri_navigations", false);
|
||||
Preferences::AddBoolVarCache(&mOfflineMirrorsConnectivity, OFFLINE_MIRRORS_CONNECTIVITY, true);
|
||||
|
||||
gIOService = this;
|
||||
|
|
@ -1876,5 +1880,11 @@ nsIOService::SpeculativeAnonymousConnect2(nsIURI *aURI,
|
|||
return SpeculativeConnectInternal(aURI, aPrincipal, aCallbacks, true);
|
||||
}
|
||||
|
||||
/*static*/ bool
|
||||
nsIOService::BlockToplevelDataUriNavigations()
|
||||
{
|
||||
return sBlockToplevelDataUriNavigations;
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
|
|
|||
|
|
@ -95,6 +95,8 @@ public:
|
|||
|
||||
bool IsLinkUp();
|
||||
|
||||
static bool BlockToplevelDataUriNavigations();
|
||||
|
||||
// Used to trigger a recheck of the captive portal status
|
||||
nsresult RecheckCaptivePortal();
|
||||
private:
|
||||
|
|
@ -176,6 +178,8 @@ private:
|
|||
|
||||
static bool sTelemetryEnabled;
|
||||
|
||||
static bool sBlockToplevelDataUriNavigations;
|
||||
|
||||
// These timestamps are needed for collecting telemetry on PR_Connect,
|
||||
// PR_ConnectContinue and PR_Close blocking time. If we spend very long
|
||||
// time in any of these functions we want to know if and what network
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue