From 2202fa3333019e8d25fe9604850e2d202ebcb45c Mon Sep 17 00:00:00 2001 From: Benjamin Date: Wed, 4 Sep 2019 20:29:37 +0000 Subject: [PATCH] Bug 1529068 - Implementation of the navigate-to CSP directive as defined in CSP Level 3. r=ckerschb,mccr8 https://www.w3.org/TR/CSP3/#directive-navigate-to Differential Revision: https://phabricator.services.mozilla.com/D37139 --HG-- extra : moz-landing-system : lando --- docshell/base/nsDocShell.cpp | 18 +- dom/base/Document.cpp | 20 +++ .../security/nsIContentSecurityPolicy.idl | 19 ++ .../en-US/chrome/security/csp.properties | 6 +- dom/security/nsCSPContext.cpp | 85 +++++++++ dom/security/nsCSPParser.cpp | 29 +++ dom/security/nsCSPService.cpp | 18 ++ dom/security/nsCSPUtils.cpp | 26 +++ dom/security/nsCSPUtils.h | 23 ++- dom/security/test/csp/file_navigate_to.html | 11 ++ dom/security/test/csp/file_navigate_to.sjs | 49 ++++++ .../test/csp/file_navigate_to_request.html | 18 ++ dom/security/test/csp/mochitest.ini | 4 + dom/security/test/csp/test_navigate_to.html | 165 ++++++++++++++++++ dom/security/test/gtest/TestCSPParser.cpp | 11 ++ modules/libpref/init/StaticPrefList.yaml | 6 + .../navigate-to/__dir__.ini | 1 + .../child-navigates-parent-allowed.html.ini | 7 +- ...hild-navigates-parent-blocked.sub.html.ini | 5 +- .../navigate-to/form-blocked.sub.html.ini | 7 - .../form-cross-origin-blocked.sub.html.ini | 10 -- .../form-redirected-blocked.sub.html.ini | 12 +- .../href-location-blocked.sub.html.ini | 7 - ...location-cross-origin-blocked.sub.html.ini | 11 +- ...f-location-redirected-blocked.sub.html.ini | 12 +- .../link-click-blocked.sub.html.ini | 7 - ...nk-click-cross-origin-blocked.sub.html.ini | 10 -- ...link-click-redirected-blocked.sub.html.ini | 12 +- .../meta-refresh-blocked.sub.html.ini | 7 - ...-refresh-cross-origin-blocked.sub.html.ini | 10 -- ...ta-refresh-redirected-blocked.sub.html.ini | 13 +- .../parent-navigates-child-blocked.html.ini | 10 -- .../spv-only-sent-to-initiator.sub.html.ini | 6 +- .../blocked-end-of-chain.sub.html.ini | 7 +- xpcom/base/ErrorList.py | 1 + 35 files changed, 545 insertions(+), 118 deletions(-) create mode 100644 dom/security/test/csp/file_navigate_to.html create mode 100644 dom/security/test/csp/file_navigate_to.sjs create mode 100644 dom/security/test/csp/file_navigate_to_request.html create mode 100644 dom/security/test/csp/test_navigate_to.html delete mode 100644 testing/web-platform/meta/content-security-policy/navigate-to/form-blocked.sub.html.ini delete mode 100644 testing/web-platform/meta/content-security-policy/navigate-to/form-cross-origin-blocked.sub.html.ini delete mode 100644 testing/web-platform/meta/content-security-policy/navigate-to/href-location-blocked.sub.html.ini delete mode 100644 testing/web-platform/meta/content-security-policy/navigate-to/link-click-blocked.sub.html.ini delete mode 100644 testing/web-platform/meta/content-security-policy/navigate-to/link-click-cross-origin-blocked.sub.html.ini delete mode 100644 testing/web-platform/meta/content-security-policy/navigate-to/meta-refresh-blocked.sub.html.ini delete mode 100644 testing/web-platform/meta/content-security-policy/navigate-to/meta-refresh-cross-origin-blocked.sub.html.ini delete mode 100644 testing/web-platform/meta/content-security-policy/navigate-to/parent-navigates-child-blocked.html.ini diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 734b80c41f35..6a3145fbb575 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -4025,7 +4025,8 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI, CopyUTF8toUTF16(host, *formatStrs.AppendElement()); error = "netTimeout"; } else if (NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION == aError || - NS_ERROR_CSP_FORM_ACTION_VIOLATION == aError) { + NS_ERROR_CSP_FORM_ACTION_VIOLATION == aError || + NS_ERROR_CSP_NAVIGATE_TO_VIOLATION == aError) { // CSP error cssClass.AssignLiteral("neterror"); error = "cspBlocked"; @@ -9867,6 +9868,21 @@ static bool HasHttpScheme(nsIURI* aURI) { nsCOMPtr csp = aLoadState->Csp(); if (csp) { + // Check CSP navigate-to + bool allowsNavigateTo = false; + aRv = csp->GetAllowsNavigateTo(aLoadState->URI(), aLoadInfo, + false, /* aWasRedirected */ + false, /* aEnforceWhitelist */ + &allowsNavigateTo); + if (NS_FAILED(aRv)) { + return false; + } + + if (!allowsNavigateTo) { + aRv = NS_ERROR_CSP_NAVIGATE_TO_VIOLATION; + return false; + } + // Navigational requests that are same origin need to be upgraded in case // upgrade-insecure-requests is present. bool upgradeInsecureRequests = false; diff --git a/dom/base/Document.cpp b/dom/base/Document.cpp index 6ba0b7a4f400..27bad866bfc3 100644 --- a/dom/base/Document.cpp +++ b/dom/base/Document.cpp @@ -3005,6 +3005,26 @@ nsresult Document::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel, nsresult rv = InitReferrerInfo(aChannel); NS_ENSURE_SUCCESS(rv, rv); + // Check CSP navigate-to + // We need to enforce the CSP of the document that initiated the load, + // which is the CSP to inherit. + nsCOMPtr cspToInherit = loadInfo->GetCspToInherit(); + if (cspToInherit) { + bool allowsNavigateTo = false; + rv = cspToInherit->GetAllowsNavigateTo( + mDocumentURI, loadInfo, + !loadInfo->RedirectChainIncludingInternalRedirects() + .IsEmpty(), /* aWasRedirected */ + true, /* aEnforceWhitelist */ + &allowsNavigateTo); + NS_ENSURE_SUCCESS(rv, rv); + + if (!allowsNavigateTo) { + aChannel->Cancel(NS_ERROR_CSP_NAVIGATE_TO_VIOLATION); + return NS_OK; + } + } + rv = InitCSP(aChannel); NS_ENSURE_SUCCESS(rv, rv); diff --git a/dom/interfaces/security/nsIContentSecurityPolicy.idl b/dom/interfaces/security/nsIContentSecurityPolicy.idl index de5c1c2bb715..786c14d9701f 100644 --- a/dom/interfaces/security/nsIContentSecurityPolicy.idl +++ b/dom/interfaces/security/nsIContentSecurityPolicy.idl @@ -62,6 +62,7 @@ interface nsIContentSecurityPolicy : nsISerializable const unsigned short BLOCK_ALL_MIXED_CONTENT = 18; const unsigned short SANDBOX_DIRECTIVE = 19; const unsigned short WORKER_SRC_DIRECTIVE = 20; + const unsigned short NAVIGATE_TO_DIRECTIVE = 21; /** * Accessor method for a read-only string version of the policy at a given @@ -145,6 +146,24 @@ interface nsIContentSecurityPolicy : nsISerializable in unsigned long aLineNumber, in unsigned long aColumnNumber); + /* + * Whether this policy allows a navigation subject to the navigate-to + * policy. + * @param aURI The target URI + * @param aLoadInfo used to check if the navigation was initiated by a form submission. This + * is important since the form-action directive overrides navigate-to in that case. + * @param aWasRedirect True if a redirect has happened. Important for path-sensitivity. + * @param aEnforceWhitelist True if the whitelist of allowed targets must be enforced. If + * this is true, the whitelist must be enforced even if 'unsafe-allow-redirects' is + * used. If 'unsafe-allow-redirects' is not used then the whitelist is always enforced + * @return + * Whether or not the effects of the navigation is allowed + */ + boolean getAllowsNavigateTo(in nsIURI aURI, + in nsILoadInfo aLoadInfo, + in boolean aWasRedirected, + in boolean aEnforceWhitelist); + /** * whether this policy allows eval and eval-like functions * such as setTimeout("code string", time). diff --git a/dom/locales/en-US/chrome/security/csp.properties b/dom/locales/en-US/chrome/security/csp.properties index f4b1f0f0dcf9..7ebcc48f739a 100644 --- a/dom/locales/en-US/chrome/security/csp.properties +++ b/dom/locales/en-US/chrome/security/csp.properties @@ -95,7 +95,11 @@ deprecatedReferrerDirective = Referrer Directive ‘%1$S’ has been deprecated. # %1$S is the name of the src that is ignored. # %2$S is the name of the directive that causes the src to be ignored. IgnoringSrcBecauseOfDirective=Ignoring ‘%1$S’ because of ‘%2$S’ directive. - +# LOCALIZATION NOTE (IgnoringSourceWithinDirective): +# %1$S is the ignored src +# %2$S is the directive which supports src +IgnoringSourceWithinDirective = Ignoring source “%1$S” (Not supported within ‘%2$S’). + # CSP Errors: # LOCALIZATION NOTE (couldntParseInvalidSource): # %1$S is the source that could not be parsed diff --git a/dom/security/nsCSPContext.cpp b/dom/security/nsCSPContext.cpp index 85c687cd7fe2..453f108bdcb4 100644 --- a/dom/security/nsCSPContext.cpp +++ b/dom/security/nsCSPContext.cpp @@ -597,6 +597,91 @@ nsCSPContext::GetAllowsInline(nsContentPolicyType aContentType, return NS_OK; } +NS_IMETHODIMP +nsCSPContext::GetAllowsNavigateTo(nsIURI* aURI, nsILoadInfo* aLoadInfo, + bool aWasRedirected, bool aEnforceWhitelist, + bool* outAllowsNavigateTo) { + /* + * The matrix below shows the different values of (aWasRedirect, + * aEnforceWhitelist) for the three different checks we do. + * + * Navigation | Start Loading | Initiate Redirect | Document + * | (nsDocShell) | (nsCSPService) | + * ----------------------------------------------------------------- + * A -> B (false,false) - (false,true) + * A -> ... -> B (false,false) (true,false) (true,true) + */ + *outAllowsNavigateTo = false; + + EnsureIPCPoliciesRead(); + // The 'form-action' directive overrules 'navigate-to' for form submissions. + // So in case this is a form submission and the directive 'form-action' is + // present then there is nothing for us to do here, see: 6.3.3.1.2 + // https://www.w3.org/TR/CSP3/#navigate-to-pre-navigate + if (aLoadInfo->GetIsFormSubmission()) { + for (unsigned long i = 0; i < mPolicies.Length(); i++) { + if (mPolicies[i]->hasDirective( + nsIContentSecurityPolicy::FORM_ACTION_DIRECTIVE)) { + *outAllowsNavigateTo = true; + return NS_OK; + } + } + } + + bool atLeastOneBlock = false; + for (unsigned long i = 0; i < mPolicies.Length(); i++) { + if (!mPolicies[i]->allowsNavigateTo(aURI, aWasRedirected, + aEnforceWhitelist)) { + if (!mPolicies[i]->getReportOnlyFlag()) { + atLeastOneBlock = true; + } + + // If the load encountered a server side redirect, the spec suggests to + // remove the path component from the URI, see: + // https://www.w3.org/TR/CSP3/#source-list-paths-and-redirects + nsCOMPtr blockedURIForReporting = aURI; + if (aWasRedirected) { + nsAutoCString prePathStr; + nsCOMPtr prePathURI; + nsresult rv = aURI->GetPrePath(prePathStr); + NS_ENSURE_SUCCESS(rv, rv); + rv = NS_NewURI(getter_AddRefs(blockedURIForReporting), prePathStr); + NS_ENSURE_SUCCESS(rv, rv); + } + + // Lines numbers and source file for the violation report + uint32_t lineNumber = 0; + uint32_t columnNumber = 0; + nsAutoCString spec; + JSContext* cx = nsContentUtils::GetCurrentJSContext(); + if (cx) { + nsJSUtils::GetCallingLocation(cx, spec, &lineNumber, &columnNumber); + // If GetCallingLocation fails linenumber & columnNumber are set to 0 + // anyway so we can skip checking if that is the case. + } + + // Report the violation + nsresult rv = AsyncReportViolation( + nullptr, // aTriggeringElement + nullptr, // aCSPEventListener + blockedURIForReporting, // aBlockedURI + nsCSPContext::BlockedContentSource::eSelf, // aBlockedSource + nullptr, // aOriginalURI + NS_LITERAL_STRING("navigate-to"), // aViolatedDirective + i, // aViolatedPolicyIndex + EmptyString(), // aObserverSubject + NS_ConvertUTF8toUTF16(spec), // aSourceFile + EmptyString(), // aScriptSample + lineNumber, // aLineNum + columnNumber); // aColumnNum + NS_ENSURE_SUCCESS(rv, rv); + } + } + + *outAllowsNavigateTo = !atLeastOneBlock; + return NS_OK; +} + /** * Reduces some code repetition for the various logging situations in * LogViolationDetails. diff --git a/dom/security/nsCSPParser.cpp b/dom/security/nsCSPParser.cpp index 3dec852400ae..ef3177cc8bf1 100644 --- a/dom/security/nsCSPParser.cpp +++ b/dom/security/nsCSPParser.cpp @@ -467,6 +467,22 @@ nsCSPBaseSrc* nsCSPParser::keywordSource() { } return new nsCSPKeywordSrc(CSP_UTF16KeywordToEnum(mCurToken)); } + + if (CSP_IsKeyword(mCurToken, CSP_UNSAFE_ALLOW_REDIRECTS)) { + if (!CSP_IsDirective(mCurDir[0], + nsIContentSecurityPolicy::NAVIGATE_TO_DIRECTIVE)) { + // Only allow 'unsafe-allow-redirects' within navigate-to. + AutoTArray params = { + NS_LITERAL_STRING("unsafe-allow-redirects"), + NS_LITERAL_STRING("navigate-to")}; + logWarningErrorToConsole(nsIScriptError::warningFlag, + "IgnoringSourceWithinDirective", params); + return nullptr; + } + + return new nsCSPKeywordSrc(CSP_UTF16KeywordToEnum(mCurToken)); + } + return nullptr; } @@ -858,6 +874,19 @@ nsCSPDirective* nsCSPParser::directiveName() { return nullptr; } + // Bug 1529068: Implement navigate-to directive. + // Once all corner cases are resolved we can remove that special + // if-handling here and let the parser just fall through to + // return new nsCSPDirective. + if (CSP_IsDirective(mCurToken, + nsIContentSecurityPolicy::NAVIGATE_TO_DIRECTIVE) && + !StaticPrefs::security_csp_enableNavigateTo()) { + AutoTArray params = {mCurToken}; + logWarningErrorToConsole(nsIScriptError::warningFlag, + "couldNotProcessUnknownDirective", params); + return nullptr; + } + // Make sure the directive does not already exist // (see http://www.w3.org/TR/CSP11/#parsing) if (mPolicy->hasDirective(CSP_StringToCSPDirective(mCurToken))) { diff --git a/dom/security/nsCSPService.cpp b/dom/security/nsCSPService.cpp index 564e27a771dd..bd8dfbfbd88d 100644 --- a/dom/security/nsCSPService.cpp +++ b/dom/security/nsCSPService.cpp @@ -252,6 +252,24 @@ CSPService::AsyncOnChannelRedirect(nsIChannel* oldChannel, nsCOMPtr loadInfo = oldChannel->LoadInfo(); + // Check CSP navigate-to + // We need to enforce the CSP of the document that initiated the load, + // which is the CSP to inherit. + nsCOMPtr cspToInherit = loadInfo->GetCspToInherit(); + if (cspToInherit) { + bool allowsNavigateTo = false; + rv = cspToInherit->GetAllowsNavigateTo(newUri, loadInfo, + true, /* aWasRedirected */ + false, /* aEnforceWhitelist */ + &allowsNavigateTo); + NS_ENSURE_SUCCESS(rv, rv); + + if (!allowsNavigateTo) { + oldChannel->Cancel(NS_ERROR_CSP_NAVIGATE_TO_VIOLATION); + return NS_OK; + } + } + // No need to continue processing if CSP is disabled or if the protocol // is *not* subject to CSP. // Please note, the correct way to opt-out of CSP using a custom diff --git a/dom/security/nsCSPUtils.cpp b/dom/security/nsCSPUtils.cpp index 35e58c05756e..fb7692aa0337 100644 --- a/dom/security/nsCSPUtils.cpp +++ b/dom/security/nsCSPUtils.cpp @@ -316,6 +316,7 @@ CSPDirective CSP_ContentTypeToDirective(nsContentPolicyType aType) { return nsIContentSecurityPolicy::NO_DIRECTIVE; // Fall through to error for all other directives + // Note that we should never end up here for navigate-to default: MOZ_ASSERT(false, "Can not map nsContentPolicyType to CSPDirective"); } @@ -1473,6 +1474,31 @@ bool nsCSPPolicy::hasDirective(CSPDirective aDir) const { return false; } +bool nsCSPPolicy::allowsNavigateTo(nsIURI* aURI, bool aWasRedirected, + bool aEnforceWhitelist) const { + bool allowsNavigateTo = true; + + for (unsigned long i = 0; i < mDirectives.Length(); i++) { + if (mDirectives[i]->equals( + nsIContentSecurityPolicy::NAVIGATE_TO_DIRECTIVE)) { + // Early return if we can skip the whitelist AND 'unsafe-allow-redirects' + // is present. + if (!aEnforceWhitelist && + mDirectives[i]->allows(CSP_UNSAFE_ALLOW_REDIRECTS, EmptyString(), + false)) { + return true; + } + // Otherwise, check against the whitelist. + if (!mDirectives[i]->permits(aURI, EmptyString(), aWasRedirected, false, + false, false)) { + allowsNavigateTo = false; + } + } + } + + return allowsNavigateTo; +} + /* * Use this function only after ::allows() returned 'false'. Most and * foremost it's used to get the violated directive before sending reports. diff --git a/dom/security/nsCSPUtils.h b/dom/security/nsCSPUtils.h index c22fcc05b0f0..717b30014ddc 100644 --- a/dom/security/nsCSPUtils.h +++ b/dom/security/nsCSPUtils.h @@ -87,7 +87,8 @@ static const char* CSPStrDirectives[] = { "child-src", // CHILD_SRC_DIRECTIVE "block-all-mixed-content", // BLOCK_ALL_MIXED_CONTENT "sandbox", // SANDBOX_DIRECTIVE - "worker-src" // WORKER_SRC_DIRECTIVE + "worker-src", // WORKER_SRC_DIRECTIVE + "navigate-to" // NAVIGATE_TO_DIRECTIVE }; inline const char* CSP_CSPDirectiveToString(CSPDirective aDir) { @@ -108,14 +109,15 @@ inline CSPDirective CSP_StringToCSPDirective(const nsAString& aDir) { return nsIContentSecurityPolicy::NO_DIRECTIVE; } -#define FOR_EACH_CSP_KEYWORD(MACRO) \ - MACRO(CSP_SELF, "'self'") \ - MACRO(CSP_UNSAFE_INLINE, "'unsafe-inline'") \ - MACRO(CSP_UNSAFE_EVAL, "'unsafe-eval'") \ - MACRO(CSP_NONE, "'none'") \ - MACRO(CSP_NONCE, "'nonce-") \ - MACRO(CSP_REPORT_SAMPLE, "'report-sample'") \ - MACRO(CSP_STRICT_DYNAMIC, "'strict-dynamic'") +#define FOR_EACH_CSP_KEYWORD(MACRO) \ + MACRO(CSP_SELF, "'self'") \ + MACRO(CSP_UNSAFE_INLINE, "'unsafe-inline'") \ + MACRO(CSP_UNSAFE_EVAL, "'unsafe-eval'") \ + MACRO(CSP_NONE, "'none'") \ + MACRO(CSP_NONCE, "'nonce-") \ + MACRO(CSP_REPORT_SAMPLE, "'report-sample'") \ + MACRO(CSP_STRICT_DYNAMIC, "'strict-dynamic'") \ + MACRO(CSP_UNSAFE_ALLOW_REDIRECTS, "'unsafe-allow-redirects'") enum CSPKeyword { #define KEYWORD_ENUM(id_, string_) id_, @@ -662,6 +664,9 @@ class nsCSPPolicy { bool visitDirectiveSrcs(CSPDirective aDir, nsCSPSrcVisitor* aVisitor) const; + bool allowsNavigateTo(nsIURI* aURI, bool aWasRedirected, + bool aEnforceWhitelist) const; + private: nsUpgradeInsecureDirective* mUpgradeInsecDir; nsTArray mDirectives; diff --git a/dom/security/test/csp/file_navigate_to.html b/dom/security/test/csp/file_navigate_to.html new file mode 100644 index 000000000000..f6ea36d389f9 --- /dev/null +++ b/dom/security/test/csp/file_navigate_to.html @@ -0,0 +1,11 @@ + + + + Bug 1529068 Implement CSP 'navigate-to' directive + + + + + diff --git a/dom/security/test/csp/file_navigate_to.sjs b/dom/security/test/csp/file_navigate_to.sjs new file mode 100644 index 000000000000..d3b3b1c2b114 --- /dev/null +++ b/dom/security/test/csp/file_navigate_to.sjs @@ -0,0 +1,49 @@ +// Custom *.sjs file specifically for the needs of +// https://bugzilla.mozilla.org/show_bug.cgi?id=1529068 + +"use strict"; +Components.utils.importGlobalProperties(["URLSearchParams"]); + +const TEST_NAVIGATION_HEAD = ` + + + + Bug 1529068 Implement CSP 'navigate-to' directive`; + +const TEST_NAVIGATION_AFTER_META = ` + + + + + + `; + +function handleRequest(request, response) { + const query = new URLSearchParams(request.queryString); + + response.setHeader("Cache-Control", "no-cache", false); + response.setHeader("Content-Type", "text/html", false); + + if (query.get("redir")) { + response.setStatusLine(request.httpVersion, "302", "Found"); + response.setHeader("Location", query.get("redir"), false); + return; + } + + response.write(TEST_NAVIGATION_HEAD); + + // We need meta to set multiple CSP headers. + if (query.get("csp")) { + response.write(""); + } + if (query.get("csp2")) { + response.write(""); + } + + response.write(TEST_NAVIGATION_AFTER_META + query.get("target") + TEST_NAVIGATION_FOOT); + +} diff --git a/dom/security/test/csp/file_navigate_to_request.html b/dom/security/test/csp/file_navigate_to_request.html new file mode 100644 index 000000000000..2a750009b2ab --- /dev/null +++ b/dom/security/test/csp/file_navigate_to_request.html @@ -0,0 +1,18 @@ + + + + + + + + + diff --git a/dom/security/test/csp/mochitest.ini b/dom/security/test/csp/mochitest.ini index b7e5b00ff80c..28ddb076388f 100644 --- a/dom/security/test/csp/mochitest.ini +++ b/dom/security/test/csp/mochitest.ini @@ -403,3 +403,7 @@ support-files = support-files = file_parent_location_js.html file_iframe_parent_location_js.html +[test_navigate_to.html] +support-files = + file_navigate_to.sjs + file_navigate_to_request.html diff --git a/dom/security/test/csp/test_navigate_to.html b/dom/security/test/csp/test_navigate_to.html new file mode 100644 index 000000000000..4ab8fce0bae9 --- /dev/null +++ b/dom/security/test/csp/test_navigate_to.html @@ -0,0 +1,165 @@ + + + + Bug 1529068 Implement CSP 'navigate-to' directive + + + + + +

+
+ +
+ + + + diff --git a/dom/security/test/gtest/TestCSPParser.cpp b/dom/security/test/gtest/TestCSPParser.cpp index d1bba155c38c..e95ba8d9b109 100644 --- a/dom/security/test/gtest/TestCSPParser.cpp +++ b/dom/security/test/gtest/TestCSPParser.cpp @@ -149,6 +149,7 @@ nsresult runTestSuite(const PolicyTest* aPolicies, uint32_t aPolicyCount, nsCOMPtr prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); bool experimentalEnabledCache = false; bool strictDynamicEnabledCache = false; + bool navigateTo = false; if (prefs) { prefs->GetBoolPref("security.csp.experimentalEnabled", &experimentalEnabledCache); @@ -157,6 +158,9 @@ nsresult runTestSuite(const PolicyTest* aPolicies, uint32_t aPolicyCount, prefs->GetBoolPref("security.csp.enableStrictDynamic", &strictDynamicEnabledCache); prefs->SetBoolPref("security.csp.enableStrictDynamic", true); + + prefs->GetBoolPref("security.csp.enableNavigateTo", &navigateTo); + prefs->SetBoolPref("security.csp.enableNavigateTo", true); } for (uint32_t i = 0; i < aPolicyCount; i++) { @@ -170,6 +174,7 @@ nsresult runTestSuite(const PolicyTest* aPolicies, uint32_t aPolicyCount, experimentalEnabledCache); prefs->SetBoolPref("security.csp.enableStrictDynamic", strictDynamicEnabledCache); + prefs->SetBoolPref("security.csp.enableNavigateTo", navigateTo); } return NS_OK; @@ -221,6 +226,12 @@ TEST(CSPParser, Directives) "worker-src https://example.com" }, { "worker-src http://worker.com; frame-src http://frame.com; child-src http://child.com", "worker-src http://worker.com; frame-src http://frame.com; child-src http://child.com" }, + { "navigate-to http://example.com", + "navigate-to http://example.com"}, + { "navigate-to 'unsafe-allow-redirects' http://example.com", + "navigate-to 'unsafe-allow-redirects' http://example.com"}, + { "script-src 'unsafe-allow-redirects' http://example.com", + "script-src http://example.com"}, // clang-format on }; diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml index 801fc6a71c63..d011deb24d23 100644 --- a/modules/libpref/init/StaticPrefList.yaml +++ b/modules/libpref/init/StaticPrefList.yaml @@ -6761,6 +6761,12 @@ value: true mirror: always +# Navigate-to CSP 3 directive +- name: security.csp.enableNavigateTo + type: bool + value: false + mirror: always + # No way to enable on Android, Bug 1552602 - name: security.webauth.u2f type: bool diff --git a/testing/web-platform/meta/content-security-policy/navigate-to/__dir__.ini b/testing/web-platform/meta/content-security-policy/navigate-to/__dir__.ini index 6c426f4142c9..199de4edf678 100644 --- a/testing/web-platform/meta/content-security-policy/navigate-to/__dir__.ini +++ b/testing/web-platform/meta/content-security-policy/navigate-to/__dir__.ini @@ -1,2 +1,3 @@ +prefs: [security.csp.enableNavigateTo:true] disabled: if (os == "win"): https://bugzilla.mozilla.org/show_bug.cgi?id=1450635 diff --git a/testing/web-platform/meta/content-security-policy/navigate-to/child-navigates-parent-allowed.html.ini b/testing/web-platform/meta/content-security-policy/navigate-to/child-navigates-parent-allowed.html.ini index feb383f40be9..d78f9d922d46 100644 --- a/testing/web-platform/meta/content-security-policy/navigate-to/child-navigates-parent-allowed.html.ini +++ b/testing/web-platform/meta/content-security-policy/navigate-to/child-navigates-parent-allowed.html.ini @@ -1,3 +1,8 @@ -[child-navigates-parent-allowed.html] +[child-navigates-parent-allowed.html] disabled: if os == "linux": https://bugzilla.mozilla.org/show_bug.cgi?id=1450660 + + expected: TIMEOUT + + [Test that the child can navigate the parent because the relevant policy belongs to the navigation initiator (in this case the child, which has the policy `navigate-to 'self'`)] + expected: NOTRUN diff --git a/testing/web-platform/meta/content-security-policy/navigate-to/child-navigates-parent-blocked.sub.html.ini b/testing/web-platform/meta/content-security-policy/navigate-to/child-navigates-parent-blocked.sub.html.ini index 7e883d43d5d7..636003547a7c 100644 --- a/testing/web-platform/meta/content-security-policy/navigate-to/child-navigates-parent-blocked.sub.html.ini +++ b/testing/web-platform/meta/content-security-policy/navigate-to/child-navigates-parent-blocked.sub.html.ini @@ -1,6 +1,9 @@ [child-navigates-parent-blocked.sub.html] disabled: if (os == "android") and not e10s: https://bugzilla.mozilla.org/show_bug.cgi?id=1511193 + + expected: TIMEOUT + [Violation report status OK.] expected: FAIL @@ -8,5 +11,5 @@ expected: FAIL [Test that the child can't navigate the parent because the relevant policy belongs to the navigation initiator (in this case the child which has the policy `navigate-to 'none'`)] - expected: FAIL + expected: NOTRUN diff --git a/testing/web-platform/meta/content-security-policy/navigate-to/form-blocked.sub.html.ini b/testing/web-platform/meta/content-security-policy/navigate-to/form-blocked.sub.html.ini deleted file mode 100644 index d6ff30e2d0b3..000000000000 --- a/testing/web-platform/meta/content-security-policy/navigate-to/form-blocked.sub.html.ini +++ /dev/null @@ -1,7 +0,0 @@ -[form-blocked.sub.html] - [Violation report status OK.] - expected: FAIL - - [Test that the child iframe navigation is not allowed] - expected: FAIL - diff --git a/testing/web-platform/meta/content-security-policy/navigate-to/form-cross-origin-blocked.sub.html.ini b/testing/web-platform/meta/content-security-policy/navigate-to/form-cross-origin-blocked.sub.html.ini deleted file mode 100644 index 5f75e13b24af..000000000000 --- a/testing/web-platform/meta/content-security-policy/navigate-to/form-cross-origin-blocked.sub.html.ini +++ /dev/null @@ -1,10 +0,0 @@ -[form-cross-origin-blocked.sub.html] - [Test that the child iframe navigation is blocked] - expected: FAIL - - [Violation report status OK.] - expected: FAIL - - [Test that the child iframe navigation is not allowed] - expected: FAIL - diff --git a/testing/web-platform/meta/content-security-policy/navigate-to/form-redirected-blocked.sub.html.ini b/testing/web-platform/meta/content-security-policy/navigate-to/form-redirected-blocked.sub.html.ini index 96b00377b64c..64e914481f64 100644 --- a/testing/web-platform/meta/content-security-policy/navigate-to/form-redirected-blocked.sub.html.ini +++ b/testing/web-platform/meta/content-security-policy/navigate-to/form-redirected-blocked.sub.html.ini @@ -1,10 +1,10 @@ [form-redirected-blocked.sub.html] + expected: + if (os == "android"): TIMEOUT [Test that the child iframe navigation is blocked] - expected: FAIL - - [Violation report status OK.] - expected: FAIL + expected: + if (os == "android"): NOTRUN [Test that the child iframe navigation is not allowed] - expected: FAIL - + expected: + if (os == "android"): NOTRUN diff --git a/testing/web-platform/meta/content-security-policy/navigate-to/href-location-blocked.sub.html.ini b/testing/web-platform/meta/content-security-policy/navigate-to/href-location-blocked.sub.html.ini deleted file mode 100644 index 0e32e7b8306f..000000000000 --- a/testing/web-platform/meta/content-security-policy/navigate-to/href-location-blocked.sub.html.ini +++ /dev/null @@ -1,7 +0,0 @@ -[href-location-blocked.sub.html] - [Violation report status OK.] - expected: FAIL - - [Test that the child iframe navigation is not allowed] - expected: FAIL - diff --git a/testing/web-platform/meta/content-security-policy/navigate-to/href-location-cross-origin-blocked.sub.html.ini b/testing/web-platform/meta/content-security-policy/navigate-to/href-location-cross-origin-blocked.sub.html.ini index aa2fc2464e3a..5b6b90cd4b46 100644 --- a/testing/web-platform/meta/content-security-policy/navigate-to/href-location-cross-origin-blocked.sub.html.ini +++ b/testing/web-platform/meta/content-security-policy/navigate-to/href-location-cross-origin-blocked.sub.html.ini @@ -1,10 +1,3 @@ [href-location-cross-origin-blocked.sub.html] - [Test that the child iframe navigation is blocked] - expected: FAIL - - [Violation report status OK.] - expected: FAIL - - [Test that the child iframe navigation is not allowed] - expected: FAIL - + disabled: + if (os == "android"): Passes on debug but fails on optimized diff --git a/testing/web-platform/meta/content-security-policy/navigate-to/href-location-redirected-blocked.sub.html.ini b/testing/web-platform/meta/content-security-policy/navigate-to/href-location-redirected-blocked.sub.html.ini index afceb246ea44..f58001275dc0 100644 --- a/testing/web-platform/meta/content-security-policy/navigate-to/href-location-redirected-blocked.sub.html.ini +++ b/testing/web-platform/meta/content-security-policy/navigate-to/href-location-redirected-blocked.sub.html.ini @@ -1,10 +1,10 @@ [href-location-redirected-blocked.sub.html] + expected: + if (os == "android"): TIMEOUT [Test that the child iframe navigation is blocked] - expected: FAIL - - [Violation report status OK.] - expected: FAIL + expected: + if (os == "android"): NOTRUN [Test that the child iframe navigation is not allowed] - expected: FAIL - + expected: + if (os == "android"): NOTRUN diff --git a/testing/web-platform/meta/content-security-policy/navigate-to/link-click-blocked.sub.html.ini b/testing/web-platform/meta/content-security-policy/navigate-to/link-click-blocked.sub.html.ini deleted file mode 100644 index 59583d54cce3..000000000000 --- a/testing/web-platform/meta/content-security-policy/navigate-to/link-click-blocked.sub.html.ini +++ /dev/null @@ -1,7 +0,0 @@ -[link-click-blocked.sub.html] - [Violation report status OK.] - expected: FAIL - - [Test that the child iframe navigation is not allowed] - expected: FAIL - diff --git a/testing/web-platform/meta/content-security-policy/navigate-to/link-click-cross-origin-blocked.sub.html.ini b/testing/web-platform/meta/content-security-policy/navigate-to/link-click-cross-origin-blocked.sub.html.ini deleted file mode 100644 index 0de26b46a7f8..000000000000 --- a/testing/web-platform/meta/content-security-policy/navigate-to/link-click-cross-origin-blocked.sub.html.ini +++ /dev/null @@ -1,10 +0,0 @@ -[link-click-cross-origin-blocked.sub.html] - [Test that the child iframe navigation is blocked] - expected: FAIL - - [Violation report status OK.] - expected: FAIL - - [Test that the child iframe navigation is not allowed] - expected: FAIL - diff --git a/testing/web-platform/meta/content-security-policy/navigate-to/link-click-redirected-blocked.sub.html.ini b/testing/web-platform/meta/content-security-policy/navigate-to/link-click-redirected-blocked.sub.html.ini index d9d16f2b3104..321809baba13 100644 --- a/testing/web-platform/meta/content-security-policy/navigate-to/link-click-redirected-blocked.sub.html.ini +++ b/testing/web-platform/meta/content-security-policy/navigate-to/link-click-redirected-blocked.sub.html.ini @@ -1,10 +1,10 @@ [link-click-redirected-blocked.sub.html] + expected: + if (os == "android"): TIMEOUT [Test that the child iframe navigation is blocked] - expected: FAIL - - [Violation report status OK.] - expected: FAIL + expected: + if (os == "android"): NOTRUN [Test that the child iframe navigation is not allowed] - expected: FAIL - + expected: + if (os == "android"): NOTRUN diff --git a/testing/web-platform/meta/content-security-policy/navigate-to/meta-refresh-blocked.sub.html.ini b/testing/web-platform/meta/content-security-policy/navigate-to/meta-refresh-blocked.sub.html.ini deleted file mode 100644 index 534ebba7b756..000000000000 --- a/testing/web-platform/meta/content-security-policy/navigate-to/meta-refresh-blocked.sub.html.ini +++ /dev/null @@ -1,7 +0,0 @@ -[meta-refresh-blocked.sub.html] - [Violation report status OK.] - expected: FAIL - - [Test that the child iframe navigation is not allowed] - expected: FAIL - diff --git a/testing/web-platform/meta/content-security-policy/navigate-to/meta-refresh-cross-origin-blocked.sub.html.ini b/testing/web-platform/meta/content-security-policy/navigate-to/meta-refresh-cross-origin-blocked.sub.html.ini deleted file mode 100644 index 0ce0a85c5619..000000000000 --- a/testing/web-platform/meta/content-security-policy/navigate-to/meta-refresh-cross-origin-blocked.sub.html.ini +++ /dev/null @@ -1,10 +0,0 @@ -[meta-refresh-cross-origin-blocked.sub.html] - [Test that the child iframe navigation is blocked] - expected: FAIL - - [Violation report status OK.] - expected: FAIL - - [Test that the child iframe navigation is not allowed] - expected: FAIL - diff --git a/testing/web-platform/meta/content-security-policy/navigate-to/meta-refresh-redirected-blocked.sub.html.ini b/testing/web-platform/meta/content-security-policy/navigate-to/meta-refresh-redirected-blocked.sub.html.ini index 4ef5b1945f6a..22396ee06d82 100644 --- a/testing/web-platform/meta/content-security-policy/navigate-to/meta-refresh-redirected-blocked.sub.html.ini +++ b/testing/web-platform/meta/content-security-policy/navigate-to/meta-refresh-redirected-blocked.sub.html.ini @@ -1,10 +1,11 @@ [meta-refresh-redirected-blocked.sub.html] - [Test that the child iframe navigation is blocked] - expected: FAIL + expected: + if (os == "android"): TIMEOUT - [Violation report status OK.] - expected: FAIL + [Test that the child iframe navigation is blocked] + expected: + if (os == "android"): NOTRUN [Test that the child iframe navigation is not allowed] - expected: FAIL - + expected: + if (os == "android"): NOTRUN diff --git a/testing/web-platform/meta/content-security-policy/navigate-to/parent-navigates-child-blocked.html.ini b/testing/web-platform/meta/content-security-policy/navigate-to/parent-navigates-child-blocked.html.ini deleted file mode 100644 index 62ee43c0c368..000000000000 --- a/testing/web-platform/meta/content-security-policy/navigate-to/parent-navigates-child-blocked.html.ini +++ /dev/null @@ -1,10 +0,0 @@ -[parent-navigates-child-blocked.html] - [Test that the parent can't navigate the child because the relevant policy belongs to the navigation initiator (in this case the parent)] - expected: FAIL - - [Violation report status OK.] - expected: FAIL - - [Test that the parent can't navigate the child because the relevant policy belongs to the navigation initiator (in this case the parent, which has the policy `navigate-to support/wait_for_navigation.html;`)] - expected: FAIL - diff --git a/testing/web-platform/meta/content-security-policy/navigate-to/spv-only-sent-to-initiator.sub.html.ini b/testing/web-platform/meta/content-security-policy/navigate-to/spv-only-sent-to-initiator.sub.html.ini index 76afc48f8e62..3ff62d334cac 100644 --- a/testing/web-platform/meta/content-security-policy/navigate-to/spv-only-sent-to-initiator.sub.html.ini +++ b/testing/web-platform/meta/content-security-policy/navigate-to/spv-only-sent-to-initiator.sub.html.ini @@ -1,5 +1,7 @@ [spv-only-sent-to-initiator.sub.html] - expected: TIMEOUT [Test that no spv event is raised] - expected: NOTRUN + expected: FAIL + + [Violation report status OK.] + expected: FAIL diff --git a/testing/web-platform/meta/content-security-policy/navigate-to/unsafe-allow-redirects/blocked-end-of-chain.sub.html.ini b/testing/web-platform/meta/content-security-policy/navigate-to/unsafe-allow-redirects/blocked-end-of-chain.sub.html.ini index 5cfe438d7c83..56492b1a2f6d 100644 --- a/testing/web-platform/meta/content-security-policy/navigate-to/unsafe-allow-redirects/blocked-end-of-chain.sub.html.ini +++ b/testing/web-platform/meta/content-security-policy/navigate-to/unsafe-allow-redirects/blocked-end-of-chain.sub.html.ini @@ -1,6 +1,9 @@ [blocked-end-of-chain.sub.html] disabled: if os == "android" and not e10s: https://bugzilla.mozilla.org/show_bug.cgi?id=1511193 - [Test that the child iframe navigation is blocked] - expected: FAIL + + expected: TIMEOUT + + [Test that the child iframe navigation is blocked] + expected: NOTRUN diff --git a/xpcom/base/ErrorList.py b/xpcom/base/ErrorList.py index f2d7ae84eef9..8b4102ab891b 100755 --- a/xpcom/base/ErrorList.py +++ b/xpcom/base/ErrorList.py @@ -792,6 +792,7 @@ with modules["PROFILE"]: # ======================================================================= with modules["SECURITY"]: # Error code for CSP + errors["NS_ERROR_CSP_NAVIGATE_TO_VIOLATION"] = FAILURE(97) errors["NS_ERROR_CSP_FORM_ACTION_VIOLATION"] = FAILURE(98) errors["NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION"] = FAILURE(99)