Bug 1578231: Hardcode whitelist of about: pages where we can not apply a CSP. r=jkt

Differential Revision: https://phabricator.services.mozilla.com/D44617

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Christoph Kerschbaumer 2019-09-05 14:22:09 +00:00
parent 035184342d
commit 4144eb70e4
4 changed files with 56 additions and 57 deletions

View File

@ -127,6 +127,9 @@ add_task(async function startup() {
min: 0,
max: 50,
},
"csp.skip_about_page_has_csp_assert": {
// This is accessed in debug only.
},
};
let startupRecorder = Cc["@mozilla.org/test/startuprecorder;1"].getService()

View File

@ -18,8 +18,6 @@
void nsContentSecurityUtils::AssertAboutPageHasCSP(Document* aDocument) {
// We want to get to a point where all about: pages ship with a CSP. This
// assertion ensures that we can not deploy new about: pages without a CSP.
// Initially we will whitelist legacy about: pages which not yet have a CSP
// attached, but ultimately that whitelist should disappear.
// Please note that any about: page should not use inline JS or inline CSS,
// and instead should load JS and CSS from an external file (*.js, *.css)
// which allows us to apply a strong CSP omitting 'unsafe-inline'. Ideally,
@ -27,43 +25,15 @@ void nsContentSecurityUtils::AssertAboutPageHasCSP(Document* aDocument) {
// should at least be as strong as:
// <meta http-equiv="Content-Security-Policy" content="default-src chrome:"/>
// Check if we are loading an about: URI at all
nsCOMPtr<nsIURI> documentURI = aDocument->GetDocumentURI();
if (!documentURI->SchemeIs("about") ||
Preferences::GetBool("csp.skip_about_page_has_csp_assert")) {
// Check if we should skip the assertion
if (Preferences::GetBool("csp.skip_about_page_has_csp_assert")) {
return;
}
// Potentially init the legacy whitelist of about URIs without a CSP.
static StaticAutoPtr<nsTArray<nsCString>> sLegacyAboutPagesWithNoCSP;
if (!sLegacyAboutPagesWithNoCSP ||
Preferences::GetBool("csp.overrule_about_uris_without_csp_whitelist")) {
sLegacyAboutPagesWithNoCSP = new nsTArray<nsCString>();
nsAutoCString legacyAboutPages;
Preferences::GetCString("csp.about_uris_without_csp", legacyAboutPages);
for (const nsACString& hostString : legacyAboutPages.Split(',')) {
// please note that for the actual whitelist we only store the path of
// about: URI. Let's reassemble the full about URI here so we don't
// have to remove query arguments later.
nsCString aboutURI;
aboutURI.AppendLiteral("about:");
aboutURI.Append(hostString);
sLegacyAboutPagesWithNoCSP->AppendElement(aboutURI);
}
ClearOnShutdown(&sLegacyAboutPagesWithNoCSP);
}
// Check if the about URI is whitelisted
nsAutoCString aboutSpec;
documentURI->GetSpec(aboutSpec);
ToLowerCase(aboutSpec);
for (auto& legacyPageEntry : *sLegacyAboutPagesWithNoCSP) {
// please note that we perform a substring match here on purpose,
// so we don't have to deal and parse out all the query arguments
// the various about pages rely on.
if (aboutSpec.Find(legacyPageEntry) == 0) {
return;
}
// Check if we are loading an about: URI at all
nsCOMPtr<nsIURI> documentURI = aDocument->GetDocumentURI();
if (!documentURI->SchemeIs("about")) {
return;
}
nsCOMPtr<nsIContentSecurityPolicy> csp = aDocument->GetCsp();
@ -80,10 +50,44 @@ void nsContentSecurityUtils::AssertAboutPageHasCSP(Document* aDocument) {
}
}
}
if (Preferences::GetBool("csp.overrule_about_uris_without_csp_whitelist")) {
// Check if we should skip the allowlist and assert right away. Please note
// that this pref can and should only be set for automated testing.
if (Preferences::GetBool("csp.skip_about_page_csp_allowlist_and_assert")) {
NS_ASSERTION(foundDefaultSrc, "about: page must have a CSP");
return;
}
nsAutoCString aboutSpec;
documentURI->GetSpec(aboutSpec);
ToLowerCase(aboutSpec);
// This allowlist contains about: pages that are permanently allowed to
// render without a CSP applied.
static nsLiteralCString sAllowedAboutPagesWithNoCSP[] = {
// about:blank is a special about page -> no CSP
NS_LITERAL_CSTRING("about:blank"),
// about:srcdoc is a special about page -> no CSP
NS_LITERAL_CSTRING("about:srcdoc"),
// about:sync-log displays plain text only -> no CSP
NS_LITERAL_CSTRING("about:sync-log"),
// about:printpreview displays plain text only -> no CSP
NS_LITERAL_CSTRING("about:printpreview"),
// Bug 1497200: Apply Meta CSP to about:downloads
NS_LITERAL_CSTRING("about:downloads"),
// Bug 1497584: Apply Meta CSP to about:preferences
NS_LITERAL_CSTRING("about:preferences"),
};
for (const nsLiteralCString& allowlistEntry : sAllowedAboutPagesWithNoCSP) {
// please note that we perform a substring match here on purpose,
// so we don't have to deal and parse out all the query arguments
// the various about pages rely on.
if (StringBeginsWith(aboutSpec, allowlistEntry)) {
return;
}
}
MOZ_ASSERT(foundDefaultSrc,
"about: page must contain a CSP including default-src");
}

View File

@ -9,31 +9,20 @@
<iframe id="testframe"></iframe>
<script class="testbody" type="text/javascript">
// Test Setup: The test overrules the allowlist of about: pages that are allowed to load
// without a CSP and makes sure to hit the assertion within AssertAboutPageHasCSP().
SpecialPowers.setBoolPref("csp.skip_about_page_csp_allowlist_and_assert", true);
SimpleTest.waitForExplicitFinish();
SimpleTest.expectAssertions(0, 1);
// Test Setup:
// The test overrules the whitelist of about: pages that are allowed to load without a CSP
// and makes sure to hit the assertion within AssertAboutPageHasCSP().
// However, due to the caching mechanism within AssertAboutPageHasCSP this
// test loads a second dummy data: URI to reset the old cache and finally resets the pref
// used for testing purposes.
let origWhiteList = SpecialPowers.getCharPref("csp.about_uris_without_csp");
SpecialPowers.setCharPref("csp.about_uris_without_csp", "");
SpecialPowers.setBoolPref("csp.overrule_about_uris_without_csp_whitelist", true);
ok(true, "sanity: prefs flipped and test runs");
let myFrame = document.getElementById("testframe");
myFrame.src = "about:blank";
// booom :-)
SpecialPowers.setCharPref("csp.about_uris_without_csp", origWhiteList);
myFrame.src = "data:text/html,<body>just a dumy data: URI</body>";
SpecialPowers.setBoolPref("csp.overrule_about_uris_without_csp_whitelist", false);
SpecialPowers.setBoolPref("csp.skip_about_page_csp_allowlist_and_assert", false);
SimpleTest.finish();
</script>
</pre>

View File

@ -2251,10 +2251,13 @@ pref("security.dialog_enable_delay", 1000);
pref("security.notification_enable_delay", 500);
#if defined(DEBUG) && !defined(ANDROID)
pref("csp.about_uris_without_csp", "blank,printpreview,srcdoc,downloads,preferences,sync-log");
// the following prefs are for testing purposes only.
pref("csp.overrule_about_uris_without_csp_whitelist", false);
// For testing purposes only: Flipping this pref to true allows
// to skip the assertion that every about page ships with a CSP.
pref("csp.skip_about_page_has_csp_assert", false);
// For testing purposes only: Flipping this pref to true allows
// to skip the allowlist for about: pages and do not ship with a
// CSP and NS_ASSERT right away.
pref("csp.skip_about_page_csp_allowlist_and_assert", false);
#endif
#ifdef EARLY_BETA_OR_EARLIER