|
@@ -0,0 +1,1160 @@
|
|
|
|
+# HG changeset patch
|
|
|
|
+# User Andrea Marchesini <amarchesini@mozilla.com>
|
|
|
|
+# Date 1525864508 -7200
|
|
|
|
+# Node ID eeaae6812d825fad8bb92be7f496f74952d82654
|
|
|
|
+# Parent 257afcbbaf6db32010d7b4ec822ac3a4e673542d
|
|
|
|
+Bug 1302449 - Remove the "referrer" directive in CSP, r=ckerschb
|
|
|
|
+
|
|
|
|
+diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp
|
|
|
|
+--- a/dom/base/nsDocument.cpp
|
|
|
|
++++ b/dom/base/nsDocument.cpp
|
|
|
|
+@@ -1417,17 +1417,16 @@ nsIDocument::nsIDocument()
|
|
|
|
+ mIsInitialDocumentInWindow(false),
|
|
|
|
+ mIgnoreDocGroupMismatches(false),
|
|
|
|
+ mLoadedAsData(false),
|
|
|
|
+ mLoadedAsInteractiveData(false),
|
|
|
|
+ mMayStartLayout(true),
|
|
|
|
+ mHaveFiredTitleChange(false),
|
|
|
|
+ mIsShowing(false),
|
|
|
|
+ mVisible(true),
|
|
|
|
+- mHasReferrerPolicyCSP(false),
|
|
|
|
+ mRemovedFromDocShell(false),
|
|
|
|
+ // mAllowDNSPrefetch starts true, so that we can always reliably && it
|
|
|
|
+ // with various values that might disable it. Since we never prefetch
|
|
|
|
+ // unless we get a window, and in that case the docshell value will get
|
|
|
|
+ // &&-ed in, this is safe.
|
|
|
|
+ mAllowDNSPrefetch(true),
|
|
|
|
+ mIsStaticDocument(false),
|
|
|
|
+ mCreatingStaticClone(false),
|
|
|
|
+@@ -2778,26 +2777,16 @@ nsDocument::ApplySettingsFromCSP(bool aS
|
|
|
|
+ {
|
|
|
|
+ nsresult rv = NS_OK;
|
|
|
|
+ if (!aSpeculative) {
|
|
|
|
+ // 1) apply settings from regular CSP
|
|
|
|
+ nsCOMPtr<nsIContentSecurityPolicy> csp;
|
|
|
|
+ rv = NodePrincipal()->GetCsp(getter_AddRefs(csp));
|
|
|
|
+ NS_ENSURE_SUCCESS_VOID(rv);
|
|
|
|
+ if (csp) {
|
|
|
|
+- // Set up any Referrer Policy specified by CSP
|
|
|
|
+- bool hasReferrerPolicy = false;
|
|
|
|
+- uint32_t referrerPolicy = mozilla::net::RP_Unset;
|
|
|
|
+- rv = csp->GetReferrerPolicy(&referrerPolicy, &hasReferrerPolicy);
|
|
|
|
+- NS_ENSURE_SUCCESS_VOID(rv);
|
|
|
|
+- if (hasReferrerPolicy) {
|
|
|
|
+- mReferrerPolicy = static_cast<ReferrerPolicy>(referrerPolicy);
|
|
|
|
+- mReferrerPolicySet = true;
|
|
|
|
+- }
|
|
|
|
+-
|
|
|
|
+ // Set up 'block-all-mixed-content' if not already inherited
|
|
|
|
+ // from the parent context or set by any other CSP.
|
|
|
|
+ if (!mBlockAllMixedContent) {
|
|
|
|
+ rv = csp->GetBlockAllMixedContent(&mBlockAllMixedContent);
|
|
|
|
+ NS_ENSURE_SUCCESS_VOID(rv);
|
|
|
|
+ }
|
|
|
|
+ if (!mBlockAllMixedContentPreloads) {
|
|
|
|
+ mBlockAllMixedContentPreloads = mBlockAllMixedContent;
|
|
|
|
+diff --git a/dom/base/nsIDocument.h b/dom/base/nsIDocument.h
|
|
|
|
+--- a/dom/base/nsIDocument.h
|
|
|
|
++++ b/dom/base/nsIDocument.h
|
|
|
|
+@@ -717,24 +717,16 @@ public:
|
|
|
|
+ * Get mixed display content blocked flag for this document.
|
|
|
|
+ */
|
|
|
|
+ bool GetHasMixedDisplayContentBlocked()
|
|
|
|
+ {
|
|
|
|
+ return mHasMixedDisplayContentBlocked;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+- * Set referrer policy CSP flag for this document.
|
|
|
|
+- */
|
|
|
|
+- void SetHasReferrerPolicyCSP(bool aHasReferrerPolicyCSP)
|
|
|
|
+- {
|
|
|
|
+- mHasReferrerPolicyCSP = aHasReferrerPolicyCSP;
|
|
|
|
+- }
|
|
|
|
+-
|
|
|
|
+- /**
|
|
|
|
+ * Set the mixed display content blocked flag for this document.
|
|
|
|
+ */
|
|
|
|
+ void SetHasMixedDisplayContentBlocked(bool aHasMixedDisplayContentBlocked)
|
|
|
|
+ {
|
|
|
|
+ mHasMixedDisplayContentBlocked = aHasMixedDisplayContentBlocked;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+@@ -3430,19 +3422,16 @@ protected:
|
|
|
|
+ // true otherwise.
|
|
|
|
+ bool mIsShowing : 1;
|
|
|
|
+
|
|
|
|
+ // State for IsVisible(). mVisible starts off true. It becomes false when
|
|
|
|
+ // OnPageHide happens, and becomes true again when OnPageShow happens. So
|
|
|
|
+ // it's false only when we're in bfcache or unloaded.
|
|
|
|
+ bool mVisible : 1;
|
|
|
|
+
|
|
|
|
+- // True if a document load has a CSP with referrer attached.
|
|
|
|
+- bool mHasReferrerPolicyCSP : 1;
|
|
|
|
+-
|
|
|
|
+ // True if our content viewer has been removed from the docshell
|
|
|
|
+ // (it may still be displayed, but in zombie state). Form control data
|
|
|
|
+ // has been saved.
|
|
|
|
+ bool mRemovedFromDocShell : 1;
|
|
|
|
+
|
|
|
|
+ // True iff DNS prefetch is allowed for this document. Note that if the
|
|
|
|
+ // document has no window, DNS prefetch won't be performed no matter what.
|
|
|
|
+ bool mAllowDNSPrefetch : 1;
|
|
|
|
+diff --git a/dom/interfaces/security/nsIContentSecurityPolicy.idl b/dom/interfaces/security/nsIContentSecurityPolicy.idl
|
|
|
|
+--- a/dom/interfaces/security/nsIContentSecurityPolicy.idl
|
|
|
|
++++ b/dom/interfaces/security/nsIContentSecurityPolicy.idl
|
|
|
|
+@@ -48,24 +48,23 @@ interface nsIContentSecurityPolicy : nsI
|
|
|
|
+ const unsigned short FRAME_SRC_DIRECTIVE = 7;
|
|
|
|
+ const unsigned short FONT_SRC_DIRECTIVE = 8;
|
|
|
|
+ const unsigned short CONNECT_SRC_DIRECTIVE = 9;
|
|
|
|
+ const unsigned short REPORT_URI_DIRECTIVE = 10;
|
|
|
|
+ const unsigned short FRAME_ANCESTORS_DIRECTIVE = 11;
|
|
|
|
+ const unsigned short REFLECTED_XSS_DIRECTIVE = 12;
|
|
|
|
+ const unsigned short BASE_URI_DIRECTIVE = 13;
|
|
|
|
+ const unsigned short FORM_ACTION_DIRECTIVE = 14;
|
|
|
|
+- const unsigned short REFERRER_DIRECTIVE = 15;
|
|
|
|
+- const unsigned short WEB_MANIFEST_SRC_DIRECTIVE = 16;
|
|
|
|
+- const unsigned short UPGRADE_IF_INSECURE_DIRECTIVE = 17;
|
|
|
|
+- const unsigned short CHILD_SRC_DIRECTIVE = 18;
|
|
|
|
+- const unsigned short BLOCK_ALL_MIXED_CONTENT = 19;
|
|
|
|
+- const unsigned short REQUIRE_SRI_FOR = 20;
|
|
|
|
+- const unsigned short SANDBOX_DIRECTIVE = 21;
|
|
|
|
+- const unsigned short WORKER_SRC_DIRECTIVE = 22;
|
|
|
|
++ const unsigned short WEB_MANIFEST_SRC_DIRECTIVE = 15;
|
|
|
|
++ const unsigned short UPGRADE_IF_INSECURE_DIRECTIVE = 16;
|
|
|
|
++ const unsigned short CHILD_SRC_DIRECTIVE = 17;
|
|
|
|
++ const unsigned short BLOCK_ALL_MIXED_CONTENT = 18;
|
|
|
|
++ const unsigned short REQUIRE_SRI_FOR = 19;
|
|
|
|
++ const unsigned short SANDBOX_DIRECTIVE = 20;
|
|
|
|
++ const unsigned short WORKER_SRC_DIRECTIVE = 21;
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Accessor method for a read-only string version of the policy at a given
|
|
|
|
+ * index.
|
|
|
|
+ */
|
|
|
|
+ [binaryname(GetPolicyString)] AString getPolicy(in unsigned long index);
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+@@ -98,31 +97,16 @@ interface nsIContentSecurityPolicy : nsI
|
|
|
|
+ readonly attribute bool blockAllMixedContent;
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Returns whether this policy enforces the frame-ancestors directive.
|
|
|
|
+ */
|
|
|
|
+ readonly attribute bool enforcesFrameAncestors;
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+- * Obtains the referrer policy (as integer) for this browsing context as
|
|
|
|
+- * specified in CSP. If there are multiple policies and...
|
|
|
|
+- * - only one sets a referrer policy: that policy is returned
|
|
|
|
+- * - more than one sets different referrer policies: no-referrer is returned
|
|
|
|
+- * - more than one set equivalent policies: that policy is returned
|
|
|
|
+- * For the enumeration of policies see ReferrerPolicy.h and nsIHttpChannel.
|
|
|
|
+- *
|
|
|
|
+- * @param aPolicy
|
|
|
|
+- * The referrer policy to use for the protected resource.
|
|
|
|
+- * @return
|
|
|
|
+- * true if a referrer policy is specified, false if it's unspecified.
|
|
|
|
+- */
|
|
|
|
+- bool getReferrerPolicy(out unsigned long policy);
|
|
|
|
+-
|
|
|
|
+- /**
|
|
|
|
+ * Parse and install a CSP policy.
|
|
|
|
+ * @param aPolicy
|
|
|
|
+ * String representation of the policy
|
|
|
|
+ * (e.g., header value, meta content)
|
|
|
|
+ * @param reportOnly
|
|
|
|
+ * Should this policy affect content, script and style processing or
|
|
|
|
+ * just send reports if it is violated?
|
|
|
|
+ * @param deliveredViaMetaTag
|
|
|
|
+diff --git a/dom/security/nsCSPContext.cpp b/dom/security/nsCSPContext.cpp
|
|
|
|
+--- a/dom/security/nsCSPContext.cpp
|
|
|
|
++++ b/dom/security/nsCSPContext.cpp
|
|
|
|
+@@ -392,58 +392,16 @@ nsCSPContext::GetEnforcesFrameAncestors(
|
|
|
|
+ *outEnforcesFrameAncestors = true;
|
|
|
|
+ return NS_OK;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return NS_OK;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ NS_IMETHODIMP
|
|
|
|
+-nsCSPContext::GetReferrerPolicy(uint32_t* outPolicy, bool* outIsSet)
|
|
|
|
+-{
|
|
|
|
+- *outIsSet = false;
|
|
|
|
+- *outPolicy = mozilla::net::RP_Unset;
|
|
|
|
+- nsAutoString refpol;
|
|
|
|
+- mozilla::net::ReferrerPolicy previousPolicy = mozilla::net::RP_Unset;
|
|
|
|
+- for (uint32_t i = 0; i < mPolicies.Length(); i++) {
|
|
|
|
+- mPolicies[i]->getReferrerPolicy(refpol);
|
|
|
|
+- // only set the referrer policy if not delievered through a CSPRO and
|
|
|
|
+- // note that and an empty string in refpol means it wasn't set
|
|
|
|
+- // (that's the default in nsCSPPolicy).
|
|
|
|
+- if (!mPolicies[i]->getReportOnlyFlag() && !refpol.IsEmpty()) {
|
|
|
|
+- // Referrer Directive in CSP is no more used and going to be replaced by
|
|
|
|
+- // Referrer-Policy HTTP header. But we still keep using referrer directive,
|
|
|
|
+- // and would remove it later.
|
|
|
|
+- // Referrer Directive specs is not fully compliant with new referrer policy
|
|
|
|
+- // specs. What we are using here:
|
|
|
|
+- // - If the value of the referrer directive is invalid, the user agent
|
|
|
|
+- // should set the referrer policy to no-referrer.
|
|
|
|
+- // - If there are two policies that specify a referrer policy, then they
|
|
|
|
+- // must agree or the employed policy is no-referrer.
|
|
|
|
+- if (!mozilla::net::IsValidReferrerPolicy(refpol)) {
|
|
|
|
+- *outPolicy = mozilla::net::RP_No_Referrer;
|
|
|
|
+- *outIsSet = true;
|
|
|
|
+- return NS_OK;
|
|
|
|
+- }
|
|
|
|
+-
|
|
|
|
+- uint32_t currentPolicy = mozilla::net::ReferrerPolicyFromString(refpol);
|
|
|
|
+- if (*outIsSet && previousPolicy != currentPolicy) {
|
|
|
|
+- *outPolicy = mozilla::net::RP_No_Referrer;
|
|
|
|
+- return NS_OK;
|
|
|
|
+- }
|
|
|
|
+-
|
|
|
|
+- *outPolicy = currentPolicy;
|
|
|
|
+- *outIsSet = true;
|
|
|
|
+- }
|
|
|
|
+- }
|
|
|
|
+-
|
|
|
|
+- return NS_OK;
|
|
|
|
+-}
|
|
|
|
+-
|
|
|
|
+-NS_IMETHODIMP
|
|
|
|
+ nsCSPContext::AppendPolicy(const nsAString& aPolicyString,
|
|
|
|
+ bool aReportOnly,
|
|
|
|
+ bool aDeliveredViaMetaTag)
|
|
|
|
+ {
|
|
|
|
+ CSPCONTEXTLOG(("nsCSPContext::AppendPolicy: %s",
|
|
|
|
+ NS_ConvertUTF16toUTF8(aPolicyString).get()));
|
|
|
|
+
|
|
|
|
+ // Use the mSelfURI from setRequestContext, see bug 991474
|
|
|
|
+diff --git a/dom/security/nsCSPParser.cpp b/dom/security/nsCSPParser.cpp
|
|
|
|
+--- a/dom/security/nsCSPParser.cpp
|
|
|
|
++++ b/dom/security/nsCSPParser.cpp
|
|
|
|
+@@ -13,17 +13,16 @@
|
|
|
|
+ #include "nsIConsoleService.h"
|
|
|
|
+ #include "nsIContentPolicy.h"
|
|
|
|
+ #include "nsIScriptError.h"
|
|
|
|
+ #include "nsIStringBundle.h"
|
|
|
|
+ #include "nsNetUtil.h"
|
|
|
|
+ #include "nsReadableUtils.h"
|
|
|
|
+ #include "nsServiceManagerUtils.h"
|
|
|
|
+ #include "nsUnicharUtils.h"
|
|
|
|
+-#include "mozilla/net/ReferrerPolicy.h"
|
|
|
|
+
|
|
|
|
+ using namespace mozilla;
|
|
|
|
+
|
|
|
|
+ static LogModule*
|
|
|
|
+ GetCspParserLog()
|
|
|
|
+ {
|
|
|
|
+ static LazyLogModule gCspParserPRLog("CSPParser");
|
|
|
|
+ return gCspParserPRLog;
|
|
|
|
+@@ -868,53 +867,16 @@ nsCSPParser::sourceList(nsTArray<nsCSPBa
|
|
|
|
+ const char16_t* params[] = { CSP_EnumToUTF16Keyword(CSP_NONE) };
|
|
|
|
+ logWarningErrorToConsole(nsIScriptError::warningFlag, "ignoringUnknownOption",
|
|
|
|
+ params, ArrayLength(params));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ void
|
|
|
|
+-nsCSPParser::referrerDirectiveValue(nsCSPDirective* aDir)
|
|
|
|
+-{
|
|
|
|
+- // directive-value = "none" / "none-when-downgrade" / "origin" / "origin-when-cross-origin" / "unsafe-url"
|
|
|
|
+- // directive name is token 0, we need to examine the remaining tokens (and
|
|
|
|
+- // there should only be one token in the value).
|
|
|
|
+- CSPPARSERLOG(("nsCSPParser::referrerDirectiveValue"));
|
|
|
|
+-
|
|
|
|
+- if (mCurDir.Length() != 2) {
|
|
|
|
+- CSPPARSERLOG(("Incorrect number of tokens in referrer directive, got %zu expected 1",
|
|
|
|
+- mCurDir.Length() - 1));
|
|
|
|
+- delete aDir;
|
|
|
|
+- return;
|
|
|
|
+- }
|
|
|
|
+-
|
|
|
|
+- if (!mozilla::net::IsValidReferrerPolicy(mCurDir[1])) {
|
|
|
|
+- CSPPARSERLOG(("invalid value for referrer directive: %s",
|
|
|
|
+- NS_ConvertUTF16toUTF8(mCurDir[1]).get()));
|
|
|
|
+- delete aDir;
|
|
|
|
+- return;
|
|
|
|
+- }
|
|
|
|
+-
|
|
|
|
+- //referrer-directive deprecation warning
|
|
|
|
+- const char16_t* params[] = { mCurDir[1].get() };
|
|
|
|
+- logWarningErrorToConsole(nsIScriptError::warningFlag, "deprecatedReferrerDirective",
|
|
|
|
+- params, ArrayLength(params));
|
|
|
|
+-
|
|
|
|
+- // the referrer policy is valid, so go ahead and use it.
|
|
|
|
+- nsWeakPtr ctx = mCSPContext->GetLoadingContext();
|
|
|
|
+- nsCOMPtr<nsIDocument> doc = do_QueryReferent(ctx);
|
|
|
|
+- if (doc) {
|
|
|
|
+- doc->SetHasReferrerPolicyCSP(true);
|
|
|
|
+- }
|
|
|
|
+- mPolicy->setReferrerPolicy(&mCurDir[1]);
|
|
|
|
+- mPolicy->addDirective(aDir);
|
|
|
|
+-}
|
|
|
|
+-
|
|
|
|
+-void
|
|
|
|
+ nsCSPParser::requireSRIForDirectiveValue(nsRequireSRIForDirective* aDir)
|
|
|
|
+ {
|
|
|
|
+ CSPPARSERLOG(("nsCSPParser::requireSRIForDirectiveValue"));
|
|
|
|
+
|
|
|
|
+ // directive-value = "style" / "script"
|
|
|
|
+ // directive name is token 0, we need to examine the remaining tokens
|
|
|
|
+ for (uint32_t i = 1; i < mCurDir.Length(); i++) {
|
|
|
|
+ // mCurToken is only set here and remains the current token
|
|
|
|
+@@ -1208,23 +1170,16 @@ nsCSPParser::directive()
|
|
|
|
+
|
|
|
|
+ // special case handling for require-sri-for, which has directive values that
|
|
|
|
+ // are well-defined tokens but are not sources
|
|
|
|
+ if (cspDir->equals(nsIContentSecurityPolicy::REQUIRE_SRI_FOR)) {
|
|
|
|
+ requireSRIForDirectiveValue(static_cast<nsRequireSRIForDirective*>(cspDir));
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+- // special case handling of the referrer directive (since it doesn't contain
|
|
|
|
+- // source lists)
|
|
|
|
+- if (cspDir->equals(nsIContentSecurityPolicy::REFERRER_DIRECTIVE)) {
|
|
|
|
+- referrerDirectiveValue(cspDir);
|
|
|
|
+- return;
|
|
|
|
+- }
|
|
|
|
+-
|
|
|
|
+ // special case handling for report-uri directive (since it doesn't contain
|
|
|
|
+ // a valid source list but rather actual URIs)
|
|
|
|
+ if (CSP_IsDirective(mCurDir[0], nsIContentSecurityPolicy::REPORT_URI_DIRECTIVE)) {
|
|
|
|
+ reportURIList(cspDir);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // special case handling for sandbox directive (since it doe4sn't contain
|
|
|
|
+diff --git a/dom/security/nsCSPUtils.cpp b/dom/security/nsCSPUtils.cpp
|
|
|
|
+--- a/dom/security/nsCSPUtils.cpp
|
|
|
|
++++ b/dom/security/nsCSPUtils.cpp
|
|
|
|
+@@ -1195,17 +1195,17 @@ nsCSPDirective::toDomCSPStruct(mozilla::
|
|
|
|
+ outCSP.mSandbox.Value() = mozilla::Move(srcs);
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ case nsIContentSecurityPolicy::WORKER_SRC_DIRECTIVE:
|
|
|
|
+ outCSP.mWorker_src.Construct();
|
|
|
|
+ outCSP.mWorker_src.Value() = mozilla::Move(srcs);
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+- // REFERRER_DIRECTIVE and REQUIRE_SRI_FOR are handled in nsCSPPolicy::toDomCSPStruct()
|
|
|
|
++ // REQUIRE_SRI_FOR is handled in nsCSPPolicy::toDomCSPStruct()
|
|
|
|
+
|
|
|
|
+ default:
|
|
|
|
+ NS_ASSERTION(false, "cannot find directive to convert CSP to JSON");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ bool
|
|
|
|
+@@ -1564,44 +1564,30 @@ nsCSPPolicy::allows(nsContentPolicyType
|
|
|
|
+ return allows(aContentType, aKeyword, NS_LITERAL_STRING(""), false);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ void
|
|
|
|
+ nsCSPPolicy::toString(nsAString& outStr) const
|
|
|
|
+ {
|
|
|
|
+ uint32_t length = mDirectives.Length();
|
|
|
|
+ for (uint32_t i = 0; i < length; ++i) {
|
|
|
|
+-
|
|
|
|
+- if (mDirectives[i]->equals(nsIContentSecurityPolicy::REFERRER_DIRECTIVE)) {
|
|
|
|
+- outStr.AppendASCII(CSP_CSPDirectiveToString(nsIContentSecurityPolicy::REFERRER_DIRECTIVE));
|
|
|
|
+- outStr.AppendASCII(" ");
|
|
|
|
+- outStr.Append(mReferrerPolicy);
|
|
|
|
+- } else {
|
|
|
|
+- mDirectives[i]->toString(outStr);
|
|
|
|
+- }
|
|
|
|
++ mDirectives[i]->toString(outStr);
|
|
|
|
+ if (i != (length - 1)) {
|
|
|
|
+ outStr.AppendASCII("; ");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ void
|
|
|
|
+ nsCSPPolicy::toDomCSPStruct(mozilla::dom::CSP& outCSP) const
|
|
|
|
+ {
|
|
|
|
+ outCSP.mReport_only = mReportOnly;
|
|
|
|
+
|
|
|
|
+ for (uint32_t i = 0; i < mDirectives.Length(); ++i) {
|
|
|
|
+- if (mDirectives[i]->equals(nsIContentSecurityPolicy::REFERRER_DIRECTIVE)) {
|
|
|
|
+- mozilla::dom::Sequence<nsString> srcs;
|
|
|
|
+- srcs.AppendElement(mReferrerPolicy, mozilla::fallible);
|
|
|
|
+- outCSP.mReferrer.Construct();
|
|
|
|
+- outCSP.mReferrer.Value() = srcs;
|
|
|
|
+- } else {
|
|
|
|
+- mDirectives[i]->toDomCSPStruct(outCSP);
|
|
|
|
+- }
|
|
|
|
++ mDirectives[i]->toDomCSPStruct(outCSP);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ bool
|
|
|
|
+ nsCSPPolicy::hasDirective(CSPDirective aDir) const
|
|
|
|
+ {
|
|
|
|
+ for (uint32_t i = 0; i < mDirectives.Length(); i++) {
|
|
|
|
+ if (mDirectives[i]->equals(aDir)) {
|
|
|
|
+diff --git a/dom/security/nsCSPUtils.h b/dom/security/nsCSPUtils.h
|
|
|
|
+--- a/dom/security/nsCSPUtils.h
|
|
|
|
++++ b/dom/security/nsCSPUtils.h
|
|
|
|
+@@ -85,17 +85,16 @@ static const char* CSPStrDirectives[] =
|
|
|
|
+ "frame-src", // FRAME_SRC_DIRECTIVE
|
|
|
|
+ "font-src", // FONT_SRC_DIRECTIVE
|
|
|
|
+ "connect-src", // CONNECT_SRC_DIRECTIVE
|
|
|
|
+ "report-uri", // REPORT_URI_DIRECTIVE
|
|
|
|
+ "frame-ancestors", // FRAME_ANCESTORS_DIRECTIVE
|
|
|
|
+ "reflected-xss", // REFLECTED_XSS_DIRECTIVE
|
|
|
|
+ "base-uri", // BASE_URI_DIRECTIVE
|
|
|
|
+ "form-action", // FORM_ACTION_DIRECTIVE
|
|
|
|
+- "referrer", // REFERRER_DIRECTIVE
|
|
|
|
+ "manifest-src", // MANIFEST_SRC_DIRECTIVE
|
|
|
|
+ "upgrade-insecure-requests", // UPGRADE_IF_INSECURE_DIRECTIVE
|
|
|
|
+ "child-src", // CHILD_SRC_DIRECTIVE
|
|
|
|
+ "block-all-mixed-content", // BLOCK_ALL_MIXED_CONTENT
|
|
|
|
+ "require-sri-for", // REQUIRE_SRI_FOR
|
|
|
|
+ "sandbox", // SANDBOX_DIRECTIVE
|
|
|
|
+ "worker-src" // WORKER_SRC_DIRECTIVE
|
|
|
|
+ };
|
|
|
|
+@@ -671,25 +670,16 @@ class nsCSPPolicy {
|
|
|
|
+ bool hasDirective(CSPDirective aDir) const;
|
|
|
|
+
|
|
|
|
+ inline void setReportOnlyFlag(bool aFlag)
|
|
|
|
+ { mReportOnly = aFlag; }
|
|
|
|
+
|
|
|
|
+ inline bool getReportOnlyFlag() const
|
|
|
|
+ { return mReportOnly; }
|
|
|
|
+
|
|
|
|
+- inline void setReferrerPolicy(const nsAString* aValue)
|
|
|
|
+- {
|
|
|
|
+- mReferrerPolicy = *aValue;
|
|
|
|
+- ToLowerCase(mReferrerPolicy);
|
|
|
|
+- }
|
|
|
|
+-
|
|
|
|
+- inline void getReferrerPolicy(nsAString& outPolicy) const
|
|
|
|
+- { outPolicy.Assign(mReferrerPolicy); }
|
|
|
|
+-
|
|
|
|
+ void getReportURIs(nsTArray<nsString> &outReportURIs) const;
|
|
|
|
+
|
|
|
|
+ void getDirectiveStringForContentType(nsContentPolicyType aContentType,
|
|
|
|
+ nsAString& outDirective) const;
|
|
|
|
+
|
|
|
|
+ void getDirectiveAsString(CSPDirective aDir, nsAString& outDirective) const;
|
|
|
|
+
|
|
|
|
+ uint32_t getSandboxFlags() const;
|
|
|
|
+@@ -700,12 +690,11 @@ class nsCSPPolicy {
|
|
|
|
+ { return mDirectives.Length(); }
|
|
|
|
+
|
|
|
|
+ bool visitDirectiveSrcs(CSPDirective aDir, nsCSPSrcVisitor* aVisitor) const;
|
|
|
|
+
|
|
|
|
+ private:
|
|
|
|
+ nsUpgradeInsecureDirective* mUpgradeInsecDir;
|
|
|
|
+ nsTArray<nsCSPDirective*> mDirectives;
|
|
|
|
+ bool mReportOnly;
|
|
|
|
+- nsString mReferrerPolicy;
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ #endif /* nsCSPUtils_h___ */
|
|
|
|
+diff --git a/dom/security/test/csp/file_referrerdirective.html b/dom/security/test/csp/file_referrerdirective.html
|
|
|
|
+deleted file mode 100644
|
|
|
|
+--- a/dom/security/test/csp/file_referrerdirective.html
|
|
|
|
++++ /dev/null
|
|
|
|
+@@ -1,55 +0,0 @@
|
|
|
|
+-<!DOCTYPE HTML>
|
|
|
|
+-<html>
|
|
|
|
+-<head>
|
|
|
|
+-<title>Subframe test for bug 965727</title>
|
|
|
|
+-
|
|
|
|
+-<script type="text/javascript">
|
|
|
|
+-// we can get the ID out of the querystring.
|
|
|
|
+-var args = document.location.search.substring(1).split('&');
|
|
|
|
+-var id = "unknown";
|
|
|
|
+-for (var i=0; i < args.length; i++) {
|
|
|
|
+- var arg = unescape(args[i]);
|
|
|
|
+- if (arg.indexOf('=') > 0 && arg.indexOf('id') == 0) {
|
|
|
|
+- id = arg.split('=')[1].trim();
|
|
|
|
+- }
|
|
|
|
+-}
|
|
|
|
+-
|
|
|
|
+-var results = {
|
|
|
|
+- 'id': id,
|
|
|
|
+- 'referrer': document.location.href,
|
|
|
|
+- 'results': {
|
|
|
|
+- 'sameorigin': false,
|
|
|
|
+- 'crossorigin': false,
|
|
|
|
+- 'downgrade': false
|
|
|
|
+- }
|
|
|
|
+-};
|
|
|
|
+-
|
|
|
|
+-// this is called back by each script load.
|
|
|
|
+-var postResult = function(loadType, referrerLevel, referrer) {
|
|
|
|
+- results.results[loadType] = referrerLevel;
|
|
|
|
+-
|
|
|
|
+- // and then check if all three have loaded.
|
|
|
|
+- for (var id in results.results) {
|
|
|
|
+- if (!results.results[id]) {
|
|
|
|
+- return;
|
|
|
|
+- }
|
|
|
|
+- }
|
|
|
|
+- //finished if we don't return early
|
|
|
|
+- window.parent.postMessage(JSON.stringify(results), "*");
|
|
|
|
+- console.log(JSON.stringify(results));
|
|
|
|
+-}
|
|
|
|
+-
|
|
|
|
+-</script>
|
|
|
|
+-</head>
|
|
|
|
+-<body>
|
|
|
|
+-Testing ...
|
|
|
|
+-
|
|
|
|
+-<script src="https://example.com/tests/dom/security/test/csp/referrerdirective.sjs?type=sameorigin&"
|
|
|
|
+- onerror="postResult('sameorigin', 'error');"></script>
|
|
|
|
+-<script src="https://test2.example.com/tests/dom/security/test/csp/referrerdirective.sjs?type=crossorigin&"
|
|
|
|
+- onerror="postResult('crossorigin', 'error');"></script>
|
|
|
|
+-<script src="http://example.com/tests/dom/security/test/csp/referrerdirective.sjs?type=downgrade&"
|
|
|
|
+- onerror="postResult('downgrade', 'error');"></script>
|
|
|
|
+-
|
|
|
|
+-</body>
|
|
|
|
+-</html>
|
|
|
|
+diff --git a/dom/security/test/csp/file_upgrade_insecure_referrer.sjs b/dom/security/test/csp/file_upgrade_insecure_referrer.sjs
|
|
|
|
+deleted file mode 100644
|
|
|
|
+--- a/dom/security/test/csp/file_upgrade_insecure_referrer.sjs
|
|
|
|
++++ /dev/null
|
|
|
|
+@@ -1,55 +0,0 @@
|
|
|
|
+-// special *.sjs specifically customized for the needs of
|
|
|
|
+-// Bug 1139297 and Bug 663570
|
|
|
|
+-
|
|
|
|
+-const PRE_HEAD =
|
|
|
|
+- "<!DOCTYPE HTML>" +
|
|
|
|
+- "<html>" +
|
|
|
|
+- "<head>";
|
|
|
|
+-
|
|
|
|
+- const POST_HEAD =
|
|
|
|
+- "<meta charset='utf-8'>" +
|
|
|
|
+- "<title>Bug 1139297 - Implement CSP upgrade-insecure-requests directive</title>" +
|
|
|
|
+- "</head>" +
|
|
|
|
+- "<body>" +
|
|
|
|
+- "<img id='testimage' src='http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_referrer_server.sjs?img'></img>" +
|
|
|
|
+- "</body>" +
|
|
|
|
+- "</html>";
|
|
|
|
+-
|
|
|
|
+-const PRE_CSP = "upgrade-insecure-requests; default-src https:; ";
|
|
|
|
+-const CSP_REFERRER_ORIGIN = "referrer origin";
|
|
|
|
+-const CSP_REFEFFER_NO_REFERRER = "referrer no-referrer";
|
|
|
|
+-
|
|
|
|
+-function handleRequest(request, response)
|
|
|
|
+-{
|
|
|
|
+- // avoid confusing cache behaviors
|
|
|
|
+- response.setHeader("Cache-Control", "no-cache", false);
|
|
|
|
+- var queryString = request.queryString;
|
|
|
|
+-
|
|
|
|
+- if (queryString === "test1") {
|
|
|
|
+- response.setHeader("Content-Security-Policy", PRE_CSP + CSP_REFERRER_ORIGIN, false);
|
|
|
|
+- response.write(PRE_HEAD + POST_HEAD);
|
|
|
|
+- return;
|
|
|
|
+- }
|
|
|
|
+-
|
|
|
|
+- if (queryString === "test2") {
|
|
|
|
+- response.setHeader("Content-Security-Policy", PRE_CSP + CSP_REFEFFER_NO_REFERRER, false);
|
|
|
|
+- response.write(PRE_HEAD + POST_HEAD);
|
|
|
|
+- return;
|
|
|
|
+- }
|
|
|
|
+-
|
|
|
|
+- if (queryString === "test3") {
|
|
|
|
+- var metacsp = "<meta http-equiv=\"Content-Security-Policy\" content = \"" + PRE_CSP + CSP_REFERRER_ORIGIN + "\" >";
|
|
|
|
+- response.write(PRE_HEAD + metacsp + POST_HEAD);
|
|
|
|
+- return;
|
|
|
|
+- }
|
|
|
|
+-
|
|
|
|
+- if (queryString === "test4") {
|
|
|
|
+- var metacsp = "<meta http-equiv=\"Content-Security-Policy\" content = \"" + PRE_CSP + CSP_REFEFFER_NO_REFERRER + "\" >";
|
|
|
|
+- response.write(PRE_HEAD + metacsp + POST_HEAD);
|
|
|
|
+- return;
|
|
|
|
+- }
|
|
|
|
+-
|
|
|
|
+- // we should never get here, but just in case return
|
|
|
|
+- // something unexpected
|
|
|
|
+- response.write("do'h");
|
|
|
|
+-}
|
|
|
|
+diff --git a/dom/security/test/csp/file_upgrade_insecure_referrer_server.sjs b/dom/security/test/csp/file_upgrade_insecure_referrer_server.sjs
|
|
|
|
+deleted file mode 100644
|
|
|
|
+--- a/dom/security/test/csp/file_upgrade_insecure_referrer_server.sjs
|
|
|
|
++++ /dev/null
|
|
|
|
+@@ -1,56 +0,0 @@
|
|
|
|
+-// Custom *.sjs file specifically for the needs of Bug:
|
|
|
|
+-// Bug 1139297 - Implement CSP upgrade-insecure-requests directive
|
|
|
|
+-
|
|
|
|
+-// small red image
|
|
|
|
+-const IMG_BYTES = atob(
|
|
|
|
+- "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12" +
|
|
|
|
+- "P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==");
|
|
|
|
+-
|
|
|
|
+-function handleRequest(request, response)
|
|
|
|
+-{
|
|
|
|
+- // avoid confusing cache behaviors
|
|
|
|
+- response.setHeader("Cache-Control", "no-cache", false);
|
|
|
|
+- var queryString = request.queryString;
|
|
|
|
+-
|
|
|
|
+- // (1) lets process the queryresult request async and
|
|
|
|
+- // wait till we have received the image request.
|
|
|
|
+- if (queryString == "queryresult") {
|
|
|
|
+- response.processAsync();
|
|
|
|
+- setObjectState("queryResult", response);
|
|
|
|
+- return;
|
|
|
|
+- }
|
|
|
|
+-
|
|
|
|
+- // (2) Handle the image request and return the referrer
|
|
|
|
+- // result back to the stored queryresult request.
|
|
|
|
+- if (request.queryString == "img") {
|
|
|
|
+- response.setHeader("Content-Type", "image/png");
|
|
|
|
+- response.write(IMG_BYTES);
|
|
|
|
+-
|
|
|
|
+- let referrer = "";
|
|
|
|
+- try {
|
|
|
|
+- referrer = request.getHeader("referer");
|
|
|
|
+- } catch (e) {
|
|
|
|
+- referrer = "";
|
|
|
|
+- }
|
|
|
|
+- // make sure the received image request was upgraded to https,
|
|
|
|
+- // otherwise we return not only the referrer but also indicate
|
|
|
|
+- // that the request was not upgraded to https. Note, that
|
|
|
|
+- // all upgrades happen in the browser before any non-secure
|
|
|
|
+- // request hits the wire.
|
|
|
|
+- referrer += (request.scheme == "https") ?
|
|
|
|
+- "" : " but request is not https";
|
|
|
|
+-
|
|
|
|
+- getObjectState("queryResult", function(queryResponse) {
|
|
|
|
+- if (!queryResponse) {
|
|
|
|
+- return;
|
|
|
|
+- }
|
|
|
|
+- queryResponse.write(referrer);
|
|
|
|
+- queryResponse.finish();
|
|
|
|
+- });
|
|
|
|
+- return;
|
|
|
|
+- }
|
|
|
|
+-
|
|
|
|
+- // we should not get here ever, but just in case return
|
|
|
|
+- // something unexpected.
|
|
|
|
+- response.write("doh!");
|
|
|
|
+-}
|
|
|
|
+diff --git a/dom/security/test/csp/mochitest.ini b/dom/security/test/csp/mochitest.ini
|
|
|
|
+--- a/dom/security/test/csp/mochitest.ini
|
|
|
|
++++ b/dom/security/test/csp/mochitest.ini
|
|
|
|
+@@ -119,26 +119,23 @@ support-files =
|
|
|
|
+ file_subframe_run_js_if_allowed.html^headers^
|
|
|
|
+ file_leading_wildcard.html
|
|
|
|
+ file_multi_policy_injection_bypass.html
|
|
|
|
+ file_multi_policy_injection_bypass.html^headers^
|
|
|
|
+ file_multi_policy_injection_bypass_2.html
|
|
|
|
+ file_multi_policy_injection_bypass_2.html^headers^
|
|
|
|
+ file_null_baseuri.html
|
|
|
|
+ file_form-action.html
|
|
|
|
+- file_referrerdirective.html
|
|
|
|
+ referrerdirective.sjs
|
|
|
|
+ file_upgrade_insecure.html
|
|
|
|
+ file_upgrade_insecure_meta.html
|
|
|
|
+ file_upgrade_insecure_server.sjs
|
|
|
|
+ file_upgrade_insecure_wsh.py
|
|
|
|
+ file_upgrade_insecure_reporting.html
|
|
|
|
+ file_upgrade_insecure_reporting_server.sjs
|
|
|
|
+- file_upgrade_insecure_referrer.sjs
|
|
|
|
+- file_upgrade_insecure_referrer_server.sjs
|
|
|
|
+ file_upgrade_insecure_cors.html
|
|
|
|
+ file_upgrade_insecure_cors_server.sjs
|
|
|
|
+ file_report_for_import.css
|
|
|
|
+ file_report_for_import.html
|
|
|
|
+ file_report_for_import_server.sjs
|
|
|
|
+ file_service_worker.html
|
|
|
|
+ file_service_worker.js
|
|
|
|
+ file_child-src_iframe.html
|
|
|
|
+@@ -267,25 +264,22 @@ skip-if = toolkit == 'android' # Times o
|
|
|
|
+ [test_301_redirect.html]
|
|
|
|
+ [test_302_redirect.html]
|
|
|
|
+ [test_303_redirect.html]
|
|
|
|
+ [test_307_redirect.html]
|
|
|
|
+ [test_subframe_run_js_if_allowed.html]
|
|
|
|
+ [test_leading_wildcard.html]
|
|
|
|
+ [test_multi_policy_injection_bypass.html]
|
|
|
|
+ [test_null_baseuri.html]
|
|
|
|
+-[test_referrerdirective.html]
|
|
|
|
+ [test_dual_header.html]
|
|
|
|
+ [test_upgrade_insecure.html]
|
|
|
|
+ # no ssl support as well as websocket tests do not work (see test_websocket.html)
|
|
|
|
+ skip-if = (toolkit == 'android') || (os != 'linux' && !debug) # Bug 1183300
|
|
|
|
+ [test_upgrade_insecure_reporting.html]
|
|
|
|
+ skip-if = toolkit == 'android'
|
|
|
|
+-[test_upgrade_insecure_referrer.html]
|
|
|
|
+-skip-if = toolkit == 'android'
|
|
|
|
+ [test_upgrade_insecure_cors.html]
|
|
|
|
+ skip-if = toolkit == 'android'
|
|
|
|
+ [test_report_for_import.html]
|
|
|
|
+ [test_blocked_uri_in_reports.html]
|
|
|
|
+ [test_service_worker.html]
|
|
|
|
+ [test_child-src_worker.html]
|
|
|
|
+ [test_child-src_worker_data.html]
|
|
|
|
+ [test_child-src_worker-redirect.html]
|
|
|
|
+diff --git a/dom/security/test/csp/test_referrerdirective.html b/dom/security/test/csp/test_referrerdirective.html
|
|
|
|
+deleted file mode 100644
|
|
|
|
+--- a/dom/security/test/csp/test_referrerdirective.html
|
|
|
|
++++ /dev/null
|
|
|
|
+@@ -1,143 +0,0 @@
|
|
|
|
+-<!--
|
|
|
|
+- Any copyright is dedicated to the Public Domain.
|
|
|
|
+- http://creativecommons.org/publicdomain/zero/1.0/
|
|
|
|
+--->
|
|
|
|
+-<!DOCTYPE HTML>
|
|
|
|
+-<html>
|
|
|
|
+-<!--
|
|
|
|
+-https://bugzilla.mozilla.org/show_bug.cgi?id=965727
|
|
|
|
+--->
|
|
|
|
+-<head>
|
|
|
|
+- <meta charset="utf-8">
|
|
|
|
+- <title>Test for Content Security Policy referrer Directive (Bug 965727)</title>
|
|
|
|
+- <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
|
|
|
+- <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
|
|
|
+-</head>
|
|
|
|
+-<body>
|
|
|
|
+-<div id="content" style="display: none">
|
|
|
|
+-
|
|
|
|
+-</div>
|
|
|
|
+-<pre id="test">
|
|
|
|
+-<script class="testbody" type="application/javascript">
|
|
|
|
+-/*
|
|
|
|
+- * This tests various referrer policies and the referrer-sending behavior when
|
|
|
|
+- * requesting scripts in different ways:
|
|
|
|
+- * - cross-origin (https://example.com -> https://test2.example.com)
|
|
|
|
+- * - same-origin (https://example.com -> https://example.com)
|
|
|
|
+- * - downgrade (https://example.com -> http://example.com)
|
|
|
|
+- *
|
|
|
|
+- * Each test creates an iframe that loads scripts for each of the checks. If
|
|
|
|
+- * the scripts are blocked, the test fails (they should run). When loaded,
|
|
|
|
+- * each script updates a results object in the test page, and then when the
|
|
|
|
+- * test page has finished loading all the scripts, it postMessages back to this
|
|
|
|
+- * page. Once all tests are done, the results are checked.
|
|
|
|
+- */
|
|
|
|
+-
|
|
|
|
+-var testData = {
|
|
|
|
+- 'default': { 'csp': "script-src * 'unsafe-inline'; referrer default",
|
|
|
|
+- 'expected': { 'sameorigin': 'full',
|
|
|
|
+- 'crossorigin': 'full',
|
|
|
|
+- 'downgrade': 'none' }},
|
|
|
|
+-
|
|
|
|
+- 'origin': { 'csp': "script-src * 'unsafe-inline'; referrer origin",
|
|
|
|
+- 'expected': { 'sameorigin': 'origin',
|
|
|
|
+- 'crossorigin': 'origin',
|
|
|
|
+- 'downgrade': 'origin' }},
|
|
|
|
+-
|
|
|
|
+- 'origin-when-cross-origin': { 'csp': "script-src * 'unsafe-inline'; referrer origin-when-cross-origin",
|
|
|
|
+- 'expected': { 'sameorigin': 'full',
|
|
|
|
+- 'crossorigin': 'origin',
|
|
|
|
+- 'downgrade': 'origin' }},
|
|
|
|
+-
|
|
|
|
+- 'unsafe-url': { 'csp': "script-src * 'unsafe-inline'; referrer unsafe-url",
|
|
|
|
+- 'expected': { 'sameorigin': 'full',
|
|
|
|
+- 'crossorigin': 'full',
|
|
|
|
+- 'downgrade': 'full' }},
|
|
|
|
+-
|
|
|
|
+- 'none': { 'csp': "script-src * 'unsafe-inline'; referrer no-referrer",
|
|
|
|
+- 'expected': { 'sameorigin': 'none',
|
|
|
|
+- 'crossorigin': 'none',
|
|
|
|
+- 'downgrade': 'none' }},
|
|
|
|
+-
|
|
|
|
+- // referrer delivered through CSPRO should be ignored
|
|
|
|
+- 'ignore-cspro': { 'cspro': "script-src * 'unsafe-inline'; referrer origin",
|
|
|
|
+- 'expected': { 'sameorigin': 'full',
|
|
|
|
+- 'crossorigin': 'full',
|
|
|
|
+- 'downgrade': 'none' }},
|
|
|
|
+-
|
|
|
|
+- // referrer delivered through CSPRO should be ignored
|
|
|
|
+- 'ignore-cspro2': { 'csp' : "script-src * 'unsafe-inline'; referrer no-referrer",
|
|
|
|
+- 'cspro': "script-src * 'unsafe-inline'; referrer origin",
|
|
|
|
+- 'expected': { 'sameorigin': 'none',
|
|
|
|
+- 'crossorigin': 'none',
|
|
|
|
+- 'downgrade': 'none' }},
|
|
|
|
+- };
|
|
|
|
+-
|
|
|
|
+-var referrerDirectiveTests = {
|
|
|
|
+- // called via postMessage when one of the iframes is done running.
|
|
|
|
+- onIframeComplete: function(event) {
|
|
|
|
+- try {
|
|
|
|
+- var results = JSON.parse(event.data);
|
|
|
|
+- ok(results.hasOwnProperty('id'), "'id' property required in posted message " + event.data);
|
|
|
|
+-
|
|
|
|
+- ok(testData.hasOwnProperty(results['id']), "Test " + results['id'] + " must be expected.");
|
|
|
|
+-
|
|
|
|
+- // check all the various load types' referrers.
|
|
|
|
+- var expected = testData[results['id']].expected;
|
|
|
|
+- for (var t in expected) {
|
|
|
|
+- is(results.results[t], expected[t],
|
|
|
|
+- " referrer must match expected for " + t + " in " + results['id']);
|
|
|
|
+- }
|
|
|
|
+- testData[results['id']]['complete'] = true;
|
|
|
|
+-
|
|
|
|
+- } catch(e) {
|
|
|
|
+- // fail -- should always be JSON
|
|
|
|
+- ok(false, "failed to parse posted message + " + event.data);
|
|
|
|
+- // have to end as well since not all messages were valid.
|
|
|
|
+- SimpleTest.finish();
|
|
|
|
+- }
|
|
|
|
+-
|
|
|
|
+- referrerDirectiveTests.checkForCompletion();
|
|
|
|
+- },
|
|
|
|
+-
|
|
|
|
+- // checks to see if all the parallel tests are done and validates results.
|
|
|
|
+- checkForCompletion: function() {
|
|
|
|
+- for (var id in testData) {
|
|
|
|
+- if (!testData[id].hasOwnProperty('complete')) {
|
|
|
|
+- return;
|
|
|
|
+- }
|
|
|
|
+- }
|
|
|
|
+- SimpleTest.finish();
|
|
|
|
+- }
|
|
|
|
+-};
|
|
|
|
+-
|
|
|
|
+-SimpleTest.waitForExplicitFinish();
|
|
|
|
+-// have to disable mixed content blocking to test https->http referrers.
|
|
|
|
+-SpecialPowers.pushPrefEnv({
|
|
|
|
+- 'set': [['security.mixed_content.block_active_content', false],
|
|
|
|
+- ['security.mixed_content.block_display_content', false],
|
|
|
|
+- ]
|
|
|
|
+- },
|
|
|
|
+- function() {
|
|
|
|
+- // each of the iframes we create will call us back when its contents are loaded.
|
|
|
|
+- window.addEventListener("message", referrerDirectiveTests.onIframeComplete.bind(window));
|
|
|
|
+-
|
|
|
|
+- // one iframe created for each test case
|
|
|
|
+- for (var id in testData) {
|
|
|
|
+- var elt = document.createElement("iframe");
|
|
|
|
+- var src = "https://example.com/tests/dom/security/test/csp/file_testserver.sjs?id=" + id;
|
|
|
|
+- if (testData[id]['csp']) {
|
|
|
|
+- src += "&csp=" + escape(testData[id]['csp']);
|
|
|
|
+- }
|
|
|
|
+- if (testData[id]['cspro']) {
|
|
|
|
+- src += "&cspro=" + escape(testData[id]['cspro']);
|
|
|
|
+- }
|
|
|
|
+- src += "&file=tests/dom/security/test/csp/file_referrerdirective.html";
|
|
|
|
+- elt.src = src;
|
|
|
|
+- document.getElementById("content").appendChild(elt);
|
|
|
|
+- }
|
|
|
|
+- });
|
|
|
|
+-</script>
|
|
|
|
+-</pre>
|
|
|
|
+-</body>
|
|
|
|
+-</html>
|
|
|
|
+diff --git a/dom/security/test/csp/test_upgrade_insecure_referrer.html b/dom/security/test/csp/test_upgrade_insecure_referrer.html
|
|
|
|
+deleted file mode 100644
|
|
|
|
+--- a/dom/security/test/csp/test_upgrade_insecure_referrer.html
|
|
|
|
++++ /dev/null
|
|
|
|
+@@ -1,85 +0,0 @@
|
|
|
|
+-<!DOCTYPE HTML>
|
|
|
|
+-<html>
|
|
|
|
+-<head>
|
|
|
|
+- <meta charset="utf-8">
|
|
|
|
+- <title>Bug 1139297 - Implement CSP upgrade-insecure-requests directive</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>
|
|
|
|
+-<iframe style="width:100%;" id="testframe"></iframe>
|
|
|
|
+-
|
|
|
|
+-<script class="testbody" type="text/javascript">
|
|
|
|
+-
|
|
|
|
+-/* Description of the test:
|
|
|
|
+- * We load a page that makes use of the CSP referrer directive as well
|
|
|
|
+- * as upgrade-insecure-requests. The page loads an image over http.
|
|
|
|
+- * The test makes sure the request gets upgraded to https and the
|
|
|
|
+- * correct referrer gets sent.
|
|
|
|
+- */
|
|
|
|
+-
|
|
|
|
+-var tests = [
|
|
|
|
+- {
|
|
|
|
+- query: "test1",
|
|
|
|
+- description: "upgrade insecure request with 'referrer = origin' (CSP in header)",
|
|
|
|
+- result: "http://example.com/"
|
|
|
|
+- },
|
|
|
|
+- {
|
|
|
|
+- query: "test2",
|
|
|
|
+- description: "upgrade insecure request with 'referrer = no-referrer' (CSP in header)",
|
|
|
|
+- result: ""
|
|
|
|
+- },
|
|
|
|
+- {
|
|
|
|
+- query: "test3",
|
|
|
|
+- description: "upgrade insecure request with 'referrer = origin' (Meta CSP)",
|
|
|
|
+- result: "http://example.com/"
|
|
|
|
+- },
|
|
|
|
+- {
|
|
|
|
+- query: "test4",
|
|
|
|
+- description: "upgrade insecure request with 'referrer = no-referrer' (Meta CSP)",
|
|
|
|
+- result: ""
|
|
|
|
+- }
|
|
|
|
+-];
|
|
|
|
+-
|
|
|
|
+-var counter = 0;
|
|
|
|
+-var curTest;
|
|
|
|
+-
|
|
|
|
+-function loadTestPage() {
|
|
|
|
+- curTest = tests[counter++];
|
|
|
|
+- var src = "http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_referrer.sjs?";
|
|
|
|
+- // append the query
|
|
|
|
+- src += curTest.query;
|
|
|
|
+- document.getElementById("testframe").src = src;
|
|
|
|
+-}
|
|
|
|
+-
|
|
|
|
+-function runNextTest() {
|
|
|
|
+- // sends a request to the server which is processed async and returns
|
|
|
|
+- // once the server received the expected image request
|
|
|
|
+- var myXHR = new XMLHttpRequest();
|
|
|
|
+- myXHR.open("GET", "file_upgrade_insecure_referrer_server.sjs?queryresult");
|
|
|
|
+- myXHR.onload = function(e) {
|
|
|
|
+- is(myXHR.responseText, curTest.result, curTest.description);
|
|
|
|
+- if (counter == tests.length) {
|
|
|
|
+- SimpleTest.finish();
|
|
|
|
+- return;
|
|
|
|
+- }
|
|
|
|
+- // move on to the next test by setting off another query request.
|
|
|
|
+- runNextTest();
|
|
|
|
+- }
|
|
|
|
+- myXHR.onerror = function(e) {
|
|
|
|
+- ok(false, "could not query results from server (" + e.message + ")");
|
|
|
|
+- SimpleTest.finish();
|
|
|
|
+- }
|
|
|
|
+- myXHR.send();
|
|
|
|
+-
|
|
|
|
+- // give it some time and load the testpage
|
|
|
|
+- SimpleTest.executeSoon(loadTestPage);
|
|
|
|
+-}
|
|
|
|
+-
|
|
|
|
+-SimpleTest.waitForExplicitFinish();
|
|
|
|
+-runNextTest();
|
|
|
|
+-
|
|
|
|
+-</script>
|
|
|
|
+-</body>
|
|
|
|
+-</html>
|
|
|
|
+diff --git a/dom/security/test/gtest/TestCSPParser.cpp b/dom/security/test/gtest/TestCSPParser.cpp
|
|
|
|
+--- a/dom/security/test/gtest/TestCSPParser.cpp
|
|
|
|
++++ b/dom/security/test/gtest/TestCSPParser.cpp
|
|
|
|
+@@ -207,18 +207,16 @@ TEST(CSPParser, Directives)
|
|
|
|
+ { "script-src 'nonce-correctscriptnonce'",
|
|
|
|
+ "script-src 'nonce-correctscriptnonce'" },
|
|
|
|
+ { "script-src 'nonce-a'",
|
|
|
|
+ "script-src 'nonce-a'" },
|
|
|
|
+ { "script-src 'sha256-a'",
|
|
|
|
+ "script-src 'sha256-a'" },
|
|
|
|
+ { "script-src 'sha256-siVR8vAcqP06h2ppeNwqgjr0yZ6yned4X2VF84j4GmI='",
|
|
|
|
+ "script-src 'sha256-siVR8vAcqP06h2ppeNwqgjr0yZ6yned4X2VF84j4GmI='" },
|
|
|
|
+- { "referrer no-referrer",
|
|
|
|
+- "referrer no-referrer" },
|
|
|
|
+ { "require-sri-for script style",
|
|
|
|
+ "require-sri-for script style"},
|
|
|
|
+ { "script-src 'nonce-foo' 'unsafe-inline' ",
|
|
|
|
+ "script-src 'nonce-foo' 'unsafe-inline'" },
|
|
|
|
+ { "script-src 'nonce-foo' 'strict-dynamic' 'unsafe-inline' https: ",
|
|
|
|
+ "script-src 'nonce-foo' 'strict-dynamic' 'unsafe-inline' https:" },
|
|
|
|
+ { "default-src 'sha256-siVR8' 'strict-dynamic' 'unsafe-inline' https: ",
|
|
|
|
+ "default-src 'sha256-siVR8' 'unsafe-inline' https:" },
|
|
|
|
+@@ -283,18 +281,16 @@ TEST(CSPParser, IgnoreUpperLowerCasePoli
|
|
|
|
+ { "script-src 'none' test.com;",
|
|
|
|
+ "script-src http://test.com" },
|
|
|
|
+ { "script-src 'NoNCE-correctscriptnonce'",
|
|
|
|
+ "script-src 'nonce-correctscriptnonce'" },
|
|
|
|
+ { "script-src 'NoncE-NONCENEEDSTOBEUPPERCASE'",
|
|
|
|
+ "script-src 'nonce-NONCENEEDSTOBEUPPERCASE'" },
|
|
|
|
+ { "script-src 'SHA256-siVR8vAcqP06h2ppeNwqgjr0yZ6yned4X2VF84j4GmI='",
|
|
|
|
+ "script-src 'sha256-siVR8vAcqP06h2ppeNwqgjr0yZ6yned4X2VF84j4GmI='" },
|
|
|
|
+- { "refERRer No-refeRRer",
|
|
|
|
+- "referrer no-referrer" },
|
|
|
|
+ { "upgrade-INSECURE-requests",
|
|
|
|
+ "upgrade-insecure-requests" },
|
|
|
|
+ { "sanDBox alloW-foRMs",
|
|
|
|
+ "sandbox allow-forms"},
|
|
|
|
+ { "require-SRI-for sCript stYle",
|
|
|
|
+ "require-sri-for script style"},
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+@@ -578,18 +574,16 @@ TEST(CSPParser, BadPolicies)
|
|
|
|
+ static const PolicyTest policies[] =
|
|
|
|
+ {
|
|
|
|
+ { "script-sr 'self", "" },
|
|
|
|
+ { "", "" },
|
|
|
|
+ { "; ; ; ; ; ; ;", "" },
|
|
|
|
+ { "defaut-src asdf", "" },
|
|
|
|
+ { "default-src: aaa", "" },
|
|
|
|
+ { "asdf http://test.com", ""},
|
|
|
|
+- { "referrer", ""},
|
|
|
|
+- { "referrer foo", ""},
|
|
|
|
+ { "require-sri-for", ""},
|
|
|
|
+ { "require-sri-for foo", ""},
|
|
|
|
+ { "report-uri", ""},
|
|
|
|
+ { "report-uri http://:foo", ""},
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest);
|
|
|
|
+ ASSERT_TRUE(NS_SUCCEEDED(runTestSuite(policies, policyCount, 0)));
|
|
|
|
+diff --git a/dom/workers/WorkerLoadInfo.cpp b/dom/workers/WorkerLoadInfo.cpp
|
|
|
|
+--- a/dom/workers/WorkerLoadInfo.cpp
|
|
|
|
++++ b/dom/workers/WorkerLoadInfo.cpp
|
|
|
|
+@@ -173,26 +173,16 @@ WorkerLoadInfo::SetPrincipalOnMainThread
|
|
|
|
+ mPrincipal = aPrincipal;
|
|
|
|
+ mPrincipalIsSystem = nsContentUtils::IsSystemPrincipal(aPrincipal);
|
|
|
|
+
|
|
|
|
+ nsresult rv = aPrincipal->GetCsp(getter_AddRefs(mCSP));
|
|
|
|
+ NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
+
|
|
|
|
+ if (mCSP) {
|
|
|
|
+ mCSP->GetAllowsEval(&mReportCSPViolations, &mEvalAllowed);
|
|
|
|
+- // Set ReferrerPolicy
|
|
|
|
+- bool hasReferrerPolicy = false;
|
|
|
|
+- uint32_t rp = mozilla::net::RP_Unset;
|
|
|
|
+-
|
|
|
|
+- rv = mCSP->GetReferrerPolicy(&rp, &hasReferrerPolicy);
|
|
|
|
+- NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
+-
|
|
|
|
+- if (hasReferrerPolicy) {
|
|
|
|
+- mReferrerPolicy = static_cast<net::ReferrerPolicy>(rp);
|
|
|
|
+- }
|
|
|
|
+ } else {
|
|
|
|
+ mEvalAllowed = true;
|
|
|
|
+ mReportCSPViolations = false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ mLoadGroup = aLoadGroup;
|
|
|
|
+
|
|
|
|
+ mPrincipalInfo = new PrincipalInfo();
|
|
|
|
+diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp
|
|
|
|
+--- a/dom/workers/WorkerPrivate.cpp
|
|
|
|
++++ b/dom/workers/WorkerPrivate.cpp
|
|
|
|
+@@ -1691,30 +1691,20 @@ WorkerPrivateParent<Derived>::SetCSPFrom
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Set evalAllowed, default value is set in GetAllowsEval
|
|
|
|
+ bool evalAllowed = false;
|
|
|
|
+ bool reportEvalViolations = false;
|
|
|
|
+ rv = csp->GetAllowsEval(&reportEvalViolations, &evalAllowed);
|
|
|
|
+ NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
+
|
|
|
|
+- // Set ReferrerPolicy, default value is set in GetReferrerPolicy
|
|
|
|
+- bool hasReferrerPolicy = false;
|
|
|
|
+- uint32_t rp = mozilla::net::RP_Unset;
|
|
|
|
+- rv = csp->GetReferrerPolicy(&rp, &hasReferrerPolicy);
|
|
|
|
+- NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
+-
|
|
|
|
+ mLoadInfo.mCSP = csp;
|
|
|
|
+ mLoadInfo.mEvalAllowed = evalAllowed;
|
|
|
|
+ mLoadInfo.mReportCSPViolations = reportEvalViolations;
|
|
|
|
+
|
|
|
|
+- if (hasReferrerPolicy) {
|
|
|
|
+- mLoadInfo.mReferrerPolicy = static_cast<net::ReferrerPolicy>(rp);
|
|
|
|
+- }
|
|
|
|
+-
|
|
|
|
+ return NS_OK;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ template <class Derived>
|
|
|
|
+ void
|
|
|
|
+ WorkerPrivateParent<Derived>::SetReferrerPolicyFromHeaderValue(
|
|
|
|
+ const nsACString& aReferrerPolicyHeaderValue)
|
|
|
|
+ {
|
|
|
|
+diff --git a/netwerk/base/ReferrerPolicy.h b/netwerk/base/ReferrerPolicy.h
|
|
|
|
+--- a/netwerk/base/ReferrerPolicy.h
|
|
|
|
++++ b/netwerk/base/ReferrerPolicy.h
|
|
|
|
+@@ -108,40 +108,16 @@ ReferrerPolicyFromString(const nsAString
|
|
|
|
+ lowerContent.EqualsLiteral(kRPS_Unsafe_URL)) {
|
|
|
|
+ return RP_Unsafe_URL;
|
|
|
|
+ }
|
|
|
|
+ // Spec says if none of the previous match, use empty string.
|
|
|
|
+ return RP_Unset;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+-inline bool
|
|
|
|
+-IsValidReferrerPolicy(const nsAString& content)
|
|
|
|
+-{
|
|
|
|
+- if (content.IsEmpty()) {
|
|
|
|
+- return true;
|
|
|
|
+- }
|
|
|
|
+-
|
|
|
|
+- nsString lowerContent(content);
|
|
|
|
+- ToLowerCase(lowerContent);
|
|
|
|
+-
|
|
|
|
+- return lowerContent.EqualsLiteral(kRPS_Never)
|
|
|
|
+- || lowerContent.EqualsLiteral(kRPS_No_Referrer)
|
|
|
|
+- || lowerContent.EqualsLiteral(kRPS_Origin)
|
|
|
|
+- || lowerContent.EqualsLiteral(kRPS_Default)
|
|
|
|
+- || lowerContent.EqualsLiteral(kRPS_No_Referrer_When_Downgrade)
|
|
|
|
+- || lowerContent.EqualsLiteral(kRPS_Origin_When_Cross_Origin)
|
|
|
|
+- || lowerContent.EqualsLiteral(kRPS_Origin_When_Crossorigin)
|
|
|
|
+- || lowerContent.EqualsLiteral(kRPS_Same_Origin)
|
|
|
|
+- || lowerContent.EqualsLiteral(kRPS_Strict_Origin)
|
|
|
|
+- || lowerContent.EqualsLiteral(kRPS_Strict_Origin_When_Cross_Origin)
|
|
|
|
+- || lowerContent.EqualsLiteral(kRPS_Always)
|
|
|
|
+- || lowerContent.EqualsLiteral(kRPS_Unsafe_URL);
|
|
|
|
+-}
|
|
|
|
+-
|
|
|
|
+ inline ReferrerPolicy
|
|
|
|
+ AttributeReferrerPolicyFromString(const nsAString& content)
|
|
|
|
+ {
|
|
|
|
+ // Specs : https://html.spec.whatwg.org/multipage/infrastructure.html#referrer-policy-attribute
|
|
|
|
+ // Spec says the empty string "" corresponds to no referrer policy, or RP_Unset
|
|
|
|
+ if (content.IsEmpty()) {
|
|
|
|
+ return RP_Unset;
|
|
|
|
+ }
|
|
|
|
+diff --git a/parser/html/nsHtml5TreeOpExecutor.cpp b/parser/html/nsHtml5TreeOpExecutor.cpp
|
|
|
|
+--- a/parser/html/nsHtml5TreeOpExecutor.cpp
|
|
|
|
++++ b/parser/html/nsHtml5TreeOpExecutor.cpp
|
|
|
|
+@@ -1171,25 +1171,16 @@ nsHtml5TreeOpExecutor::AddSpeculationCSP
|
|
|
|
+
|
|
|
|
+ // please note that meta CSPs and CSPs delivered through a header need
|
|
|
|
+ // to be joined together.
|
|
|
|
+ rv = preloadCsp->AppendPolicy(aCSP,
|
|
|
|
+ false, // csp via meta tag can not be report only
|
|
|
|
+ true); // delivered through the meta tag
|
|
|
|
+ NS_ENSURE_SUCCESS_VOID(rv);
|
|
|
|
+
|
|
|
|
+- // Record "speculated" referrer policy for preloads
|
|
|
|
+- bool hasReferrerPolicy = false;
|
|
|
|
+- uint32_t referrerPolicy = mozilla::net::RP_Unset;
|
|
|
|
+- rv = preloadCsp->GetReferrerPolicy(&referrerPolicy, &hasReferrerPolicy);
|
|
|
|
+- NS_ENSURE_SUCCESS_VOID(rv);
|
|
|
|
+- if (hasReferrerPolicy) {
|
|
|
|
+- SetSpeculationReferrerPolicy(static_cast<ReferrerPolicy>(referrerPolicy));
|
|
|
|
+- }
|
|
|
|
+-
|
|
|
|
+ mDocument->ApplySettingsFromCSP(true);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ void
|
|
|
|
+ nsHtml5TreeOpExecutor::SetSpeculationReferrerPolicy(ReferrerPolicy aReferrerPolicy)
|
|
|
|
+ {
|
|
|
|
+ // Record "speculated" referrer policy locally and thread through the
|
|
|
|
+ // speculation phase. The actual referrer policy will be set by
|
|
|
|
+diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json
|
|
|
|
+--- a/toolkit/components/telemetry/Histograms.json
|
|
|
|
++++ b/toolkit/components/telemetry/Histograms.json
|
|
|
|
+@@ -2627,24 +2627,16 @@
|
|
|
|
+ "CSP_UNSAFE_EVAL_DOCUMENTS_COUNT": {
|
|
|
|
+ "record_in_processes": ["main", "content"],
|
|
|
|
+ "alert_emails": ["seceng-telemetry@mozilla.com"],
|
|
|
|
+ "bug_numbers": [1252829],
|
|
|
|
+ "expires_in_version": "60",
|
|
|
|
+ "kind": "count",
|
|
|
|
+ "description": "Number of unique pages that contain an unsafe-eval CSP directive"
|
|
|
|
+ },
|
|
|
|
+- "CSP_REFERRER_DIRECTIVE": {
|
|
|
|
+- "record_in_processes": ["main", "content"],
|
|
|
|
+- "alert_emails": ["seceng-telemetry@mozilla.com"],
|
|
|
|
+- "bug_numbers": [1303685],
|
|
|
|
+- "expires_in_version": "60",
|
|
|
|
+- "kind": "boolean",
|
|
|
|
+- "description": "Whether a document with a CSP policy (report-only or enforcing) contains a referrer directive ('true') or not ('false')."
|
|
|
|
+- },
|
|
|
|
+ "LINK_ICON_SIZES_ATTR_USAGE": {
|
|
|
|
+ "record_in_processes": ["main", "content"],
|
|
|
|
+ "expires_in_version" : "never",
|
|
|
|
+ "kind": "enumerated",
|
|
|
|
+ "n_values": 4,
|
|
|
|
+ "description": "The possible types of the 'sizes' attribute for <link rel=icon>. 0: Attribute not specified, 1: 'any', 2: Integer dimensions, 3: Invalid value."
|
|
|
|
+ },
|
|
|
|
+ "LINK_ICON_SIZES_ATTR_DIMENSION": {
|