mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:18:48 +00:00
import changes from `dev' branch of rmottola/Arctic-Fox:
- remove a fix of PM now part of original bug 1280454 (63a48bffc) - Bug 1004703 - ignore 'unsafe-inline' if nonce- or hash-source specified (r=sstamm) (26c3f1d83) - Bug 1139297 - Implement CSP upgrade-insecure-requests directive - document changes (r=smaug) Bug 1139297 - Implement CSP upgrade-insecure-requests directive - csp changes (r=sstamm) (6ae99cb91) - Bug 1175480 - Expose the external content policy type from the load info objects; r=smaug (bad7acb0b) - Bug 1139297 - Implement CSP upgrade-insecure-requests directive - loadinfo changes (r=sicking,sworkman) (f1e5caa97) - Bug 1139297 - Implement CSP upgrade-insecure-requests directive - mcb changes (r=tanvi) (3c3086263) - Bug 1139297 - Implement CSP upgrade-insecure-requests directive - cors changes (r=smaug) (7181cf6af) - Bug 1159945 - Add telemetry to measure HSTS usage (9950700e5) - Bug 1139297 - Implement CSP upgrade-insecure-requests directive - netwerk changes (r=sworkman) (e8a18ecec) - Bug 1139297 - Implement CSP upgrade-insecure-requests directive - websocket changes (r=baku) (e2175bc25) - Bug 1139297 - Implement CSP upgrade-insecure-requests directive - form changes (r=baku) (80e178c19) - Bug 1139297 - Implement CSP upgrade-insecure-requests directive - devtool changes (r=sstamm,bholley) (ab9ed53dd) - Bug 1168538 - Add compiled code test for referrer directive to TestCSPParser. r=ckerschb (964893684) - Bug 1139297 - Implement CSP upgrade-insecure-requests directive - parser tests (r=sstamm) (b1e0342c9) - Bug 1139297 - Implement CSP upgrade-insecure-requests directive - simple upgrade tests (r=tanvi,sstamm) (8e3dfedc8) - Bug 1139297 - Implement CSP upgrade-insecure-requests directive - reports (r=sstamm) (949e85987) - Bug 1139297 - Implement CSP upgrade-insecure-requests directive - tests referrer (r=sstamm) (835f4d143) - Bug 1139297 - Implement CSP upgrade-insecure-requests directive - cors tests (r=smaug) (18054ab57) - Bug 1179123 - Avoid crash when calling ExitFullscreenInDocTree with a detached fullscreen document with its root exited fullscreen state. r=smaug (cb84e0aa7) - Bug 1173215, don't set mChromeXHRDocURI when dealing with non-XHR documents, r=bz (cbe06329e) - Bug 1178860 - Add dom.meta-viewport.enabled to gfxPrefs. r=dvander (060738800) - Bug 1175228: Skip profiler_tracing call for requestAnimationFrame callbacks, if we don't have any callbacks. r=BenWa (b52166626) - Bug 1175245: Convert nsRefreshDriver.cpp to use range-based "for" loops. r=tn (b5366155b) - Bug 1177764 - Use nsTObserverArray in APZCCallbackHelper, r=kats, r=dholbert (745e67b73)
This commit is contained in:
+63
-34
@@ -14,6 +14,8 @@
|
||||
#include "mozilla/DOMEventTargetHelper.h"
|
||||
#include "mozilla/net/WebSocketChannel.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/nsCSPContext.h"
|
||||
#include "mozilla/dom/nsCSPUtils.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/dom/WorkerPrivate.h"
|
||||
#include "mozilla/dom/WorkerRunnable.h"
|
||||
@@ -1506,6 +1508,67 @@ WebSocketImpl::Init(JSContext* aCx,
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
{
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(uri), mURI);
|
||||
|
||||
// We crash here because we are sure that mURI is a valid URI, so either we
|
||||
// are OOM'ing or something else bad is happening.
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
|
||||
// Check content policy.
|
||||
int16_t shouldLoad = nsIContentPolicy::ACCEPT;
|
||||
nsCOMPtr<nsIDocument> originDoc = nsContentUtils::GetDocumentFromScriptContext(sc);
|
||||
mOriginDocument = do_GetWeakReference(originDoc);
|
||||
aRv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_WEBSOCKET,
|
||||
uri,
|
||||
aPrincipal,
|
||||
originDoc,
|
||||
EmptyCString(),
|
||||
nullptr,
|
||||
&shouldLoad,
|
||||
nsContentUtils::GetContentPolicy(),
|
||||
nsContentUtils::GetSecurityManager());
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (NS_CP_REJECTED(shouldLoad)) {
|
||||
// Disallowed by content policy.
|
||||
aRv.Throw(NS_ERROR_CONTENT_BLOCKED);
|
||||
return;
|
||||
}
|
||||
|
||||
// Potentially the page uses the CSP directive 'upgrade-insecure-requests'.
|
||||
// In such a case we have to upgrade ws: to wss: and also update mSecure
|
||||
// to reflect that upgrade. Please note that we can not upgrade from ws:
|
||||
// to wss: before performing content policy checks because CSP needs to
|
||||
// send reports in case the scheme is about to be upgraded.
|
||||
if (!mSecure && originDoc && originDoc->GetUpgradeInsecureRequests()) {
|
||||
// let's use the old specification before the upgrade for logging
|
||||
NS_ConvertUTF8toUTF16 reportSpec(mURI);
|
||||
|
||||
// upgrade the request from ws:// to wss:// and mark as secure
|
||||
mURI.ReplaceSubstring("ws://", "wss://");
|
||||
if (NS_WARN_IF(mURI.Find("wss://") != 0)) {
|
||||
return;
|
||||
}
|
||||
mSecure = true;
|
||||
|
||||
const char16_t* params[] = { reportSpec.get(), NS_LITERAL_STRING("wss").get() };
|
||||
CSP_LogLocalizedStr(NS_LITERAL_STRING("upgradeInsecureRequest").get(),
|
||||
params, ArrayLength(params),
|
||||
EmptyString(), // aSourceFile
|
||||
EmptyString(), // aScriptSample
|
||||
0, // aLineNumber
|
||||
0, // aColumnNumber
|
||||
nsIScriptError::warningFlag, "CSP",
|
||||
mInnerWindowID);
|
||||
}
|
||||
|
||||
// Don't allow https:// to open ws://
|
||||
if (!mSecure &&
|
||||
!Preferences::GetBool("network.websocket.allowInsecureFromHTTPS",
|
||||
@@ -1558,40 +1621,6 @@ WebSocketImpl::Init(JSContext* aCx,
|
||||
AppendUTF16toUTF8(aProtocolArray[index], mRequestedProtocolList);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
{
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(uri), mURI);
|
||||
|
||||
// We crash here because we are sure that mURI is a valid URI, so either we
|
||||
// are OOM'ing or something else bad is happening.
|
||||
if (NS_FAILED(rv)) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
|
||||
// Check content policy.
|
||||
int16_t shouldLoad = nsIContentPolicy::ACCEPT;
|
||||
nsCOMPtr<nsIDocument> originDoc = nsContentUtils::GetDocumentFromScriptContext(sc);
|
||||
mOriginDocument = do_GetWeakReference(originDoc);
|
||||
aRv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_WEBSOCKET,
|
||||
uri,
|
||||
aPrincipal,
|
||||
originDoc,
|
||||
EmptyCString(),
|
||||
nullptr,
|
||||
&shouldLoad,
|
||||
nsContentUtils::GetContentPolicy(),
|
||||
nsContentUtils::GetSecurityManager());
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (NS_CP_REJECTED(shouldLoad)) {
|
||||
// Disallowed by content policy.
|
||||
aRv.Throw(NS_ERROR_CONTENT_BLOCKED);
|
||||
return;
|
||||
}
|
||||
|
||||
// the constructor should throw a SYNTAX_ERROR only if it fails to parse the
|
||||
// url parameter, so don't throw if InitializeConnection fails, and call
|
||||
// onerror/onclose asynchronously
|
||||
|
||||
+36
-5
@@ -231,6 +231,7 @@
|
||||
#include "mozilla/dom/FontFaceSet.h"
|
||||
#include "mozilla/dom/BoxObject.h"
|
||||
#include "gfxVR.h"
|
||||
#include "gfxPrefs.h"
|
||||
|
||||
#include "nsISpeculativeConnect.h"
|
||||
|
||||
@@ -1535,6 +1536,7 @@ nsIDocument::nsIDocument()
|
||||
: nsINode(nullNodeInfo),
|
||||
mReferrerPolicySet(false),
|
||||
mReferrerPolicy(mozilla::net::RP_Default),
|
||||
mUpgradeInsecureRequests(false),
|
||||
mCharacterSet(NS_LITERAL_CSTRING("ISO-8859-1")),
|
||||
mNodeInfoManager(nullptr),
|
||||
mCompatMode(eCompatibility_FullStandards),
|
||||
@@ -2264,7 +2266,7 @@ nsDocument::Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup)
|
||||
NS_GET_IID(nsIURI), getter_AddRefs(baseURI));
|
||||
if (baseURI) {
|
||||
mDocumentBaseURI = baseURI;
|
||||
mChromeXHRDocBaseURI = baseURI;
|
||||
mChromeXHRDocBaseURI = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2346,7 +2348,7 @@ nsDocument::ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup,
|
||||
mOriginalURI = nullptr;
|
||||
|
||||
SetDocumentURI(aURI);
|
||||
mChromeXHRDocURI = aURI;
|
||||
mChromeXHRDocURI = nullptr;
|
||||
// If mDocumentBaseURI is null, nsIDocument::GetBaseURI() returns
|
||||
// mDocumentURI.
|
||||
mDocumentBaseURI = nullptr;
|
||||
@@ -2686,6 +2688,19 @@ nsDocument::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel,
|
||||
WarnIfSandboxIneffective(docShell, mSandboxFlags, GetChannel());
|
||||
}
|
||||
|
||||
// The CSP directive upgrade-insecure-requests not only applies to the
|
||||
// toplevel document, but also to nested documents. Let's propagate that
|
||||
// flag from the parent to the nested document.
|
||||
nsCOMPtr<nsIDocShellTreeItem> treeItem = this->GetDocShell();
|
||||
if (treeItem) {
|
||||
nsCOMPtr<nsIDocShellTreeItem> sameTypeParent;
|
||||
treeItem->GetSameTypeParent(getter_AddRefs(sameTypeParent));
|
||||
if (sameTypeParent) {
|
||||
mUpgradeInsecureRequests =
|
||||
sameTypeParent->GetDocument()->GetUpgradeInsecureRequests();
|
||||
}
|
||||
}
|
||||
|
||||
// If this is not a data document, set CSP.
|
||||
if (!mLoadedAsData) {
|
||||
nsresult rv = InitCSP(aChannel);
|
||||
@@ -2968,6 +2983,13 @@ nsDocument::InitCSP(nsIChannel* aChannel)
|
||||
// speculative loads.
|
||||
}
|
||||
|
||||
// ------ Set flag for 'upgrade-insecure-requests' if not already
|
||||
// inherited from the parent context.
|
||||
if (!mUpgradeInsecureRequests) {
|
||||
rv = csp->GetUpgradeInsecureRequests(&mUpgradeInsecureRequests);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
rv = principal->SetCsp(csp);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
MOZ_LOG(gCspPRLog, LogLevel::Debug,
|
||||
@@ -7900,7 +7922,7 @@ nsDocument::GetViewportInfo(const ScreenIntSize& aDisplaySize)
|
||||
/*allowDoubleTapZoom*/ true);
|
||||
}
|
||||
|
||||
if (!Preferences::GetBool("dom.meta-viewport.enabled", false)) {
|
||||
if (!gfxPrefs::MetaViewportEnabled()) {
|
||||
return nsViewportInfo(aDisplaySize,
|
||||
defaultScale,
|
||||
/*allowZoom*/ false,
|
||||
@@ -11267,8 +11289,17 @@ ExitFullscreenInDocTree(nsIDocument* aMaybeNotARootDoc)
|
||||
if (!root) {
|
||||
return;
|
||||
}
|
||||
NS_ASSERTION(root->IsFullScreenDoc(),
|
||||
"Fullscreen root should be a fullscreen doc...");
|
||||
if (!root->IsFullScreenDoc()) {
|
||||
// If a document was detached before exiting from fullscreen, it is
|
||||
// possible that the root had left fullscreen state. In this case,
|
||||
// we would not get anything from the ResetFullScreen() call. Root's
|
||||
// not being a fullscreen doc also means the widget should have
|
||||
// exited fullscreen state. It means even if we do not return here,
|
||||
// we would actually do nothing below except crashing ourselves via
|
||||
// dispatching the "MozDOMFullscreen:Exited" event to an nonexistent
|
||||
// document.
|
||||
return;
|
||||
}
|
||||
|
||||
// Stores a list of documents to which we must dispatch "mozfullscreenchange".
|
||||
// We're required by the spec to dispatch the events in leaf-to-root
|
||||
|
||||
+12
-2
@@ -317,8 +317,16 @@ public:
|
||||
return GetReferrerPolicy();
|
||||
}
|
||||
|
||||
void SetReferrer(const nsACString& aReferrer) {
|
||||
mReferrer = aReferrer;
|
||||
/**
|
||||
* If true, this flag indicates that all subresource loads for this
|
||||
* document need to be upgraded from http to https.
|
||||
* This flag becomes true if the CSP of the document itself, or any
|
||||
* of the document's ancestors up to the toplevel document makes use
|
||||
* of the CSP directive 'upgrade-insecure-requests'.
|
||||
*/
|
||||
bool GetUpgradeInsecureRequests() const
|
||||
{
|
||||
return mUpgradeInsecureRequests;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2691,6 +2699,8 @@ protected:
|
||||
bool mReferrerPolicySet;
|
||||
ReferrerPolicyEnum mReferrerPolicy;
|
||||
|
||||
bool mUpgradeInsecureRequests;
|
||||
|
||||
mozilla::WeakPtr<nsDocShell> mDocumentContainer;
|
||||
|
||||
nsCString mCharacterSet;
|
||||
|
||||
@@ -2218,9 +2218,6 @@ nsXMLHttpRequest::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
|
||||
!(mState & XML_HTTP_REQUEST_USE_XSITE_AC));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// the spec requires the response document.referrer to be the empty string
|
||||
mResponseXML->SetReferrer(NS_LITERAL_CSTRING(""));
|
||||
|
||||
mXMLParserStreamListener = listener;
|
||||
rv = mXMLParserStreamListener->OnStartRequest(request, ctxt);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
@@ -486,6 +486,14 @@ function runTest() {
|
||||
xhr.send();
|
||||
yield undefined;
|
||||
|
||||
history.pushState({}, "pushStateTest", window.location.href + "/pushStateTest");
|
||||
ok(document.documentURI.indexOf("pushStateTest") > -1);
|
||||
|
||||
var chromeDoc = SpecialPowers.wrap(document);
|
||||
ok(chromeDoc.documentURI.indexOf("pushStateTest") > -1);
|
||||
|
||||
history.back();
|
||||
|
||||
SimpleTest.finish();
|
||||
SpecialPowers.removePermission("systemXHR", document);
|
||||
yield undefined;
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
#include "mozilla/EventStateManager.h"
|
||||
#include "mozilla/EventStates.h"
|
||||
#include "mozilla/dom/AutocompleteErrorEvent.h"
|
||||
#include "mozilla/dom/nsCSPUtils.h"
|
||||
#include "mozilla/dom/nsCSPContext.h"
|
||||
#include "mozilla/dom/HTMLFormControlsCollection.h"
|
||||
#include "mozilla/dom/HTMLFormElementBinding.h"
|
||||
#include "mozilla/Move.h"
|
||||
@@ -41,6 +43,7 @@
|
||||
#include "nsCategoryManagerUtils.h"
|
||||
#include "nsISimpleEnumerator.h"
|
||||
#include "nsRange.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsIInterfaceRequestorUtils.h"
|
||||
@@ -1745,6 +1748,40 @@ HTMLFormElement::GetActionURL(nsIURI** aActionURL,
|
||||
}
|
||||
}
|
||||
|
||||
// Potentially the page uses the CSP directive 'upgrade-insecure-requests'. In
|
||||
// such a case we have to upgrade the action url from http:// to https://.
|
||||
// If the actionURL is not http, then there is nothing to do.
|
||||
bool isHttpScheme = false;
|
||||
rv = actionURL->SchemeIs("http", &isHttpScheme);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (isHttpScheme && document->GetUpgradeInsecureRequests()) {
|
||||
// let's use the old specification before the upgrade for logging
|
||||
nsAutoCString spec;
|
||||
rv = actionURL->GetSpec(spec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ConvertUTF8toUTF16 reportSpec(spec);
|
||||
|
||||
// upgrade the actionURL from http:// to use https://
|
||||
rv = actionURL->SetScheme(NS_LITERAL_CSTRING("https"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// let's log a message to the console that we are upgrading a request
|
||||
nsAutoCString scheme;
|
||||
rv = actionURL->GetScheme(scheme);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ConvertUTF8toUTF16 reportScheme(scheme);
|
||||
|
||||
const char16_t* params[] = { reportSpec.get(), reportScheme.get() };
|
||||
CSP_LogLocalizedStr(NS_LITERAL_STRING("upgradeInsecureRequest").get(),
|
||||
params, ArrayLength(params),
|
||||
EmptyString(), // aSourceFile
|
||||
EmptyString(), // aScriptSample
|
||||
0, // aLineNumber
|
||||
0, // aColumnNumber
|
||||
nsIScriptError::warningFlag, "CSP",
|
||||
document->InnerWindowID());
|
||||
}
|
||||
|
||||
//
|
||||
// Assign to the output
|
||||
//
|
||||
|
||||
@@ -175,10 +175,9 @@ SetBaseURIUsingFirstBaseWithHref(nsIDocument* aDocument, nsIContent* aMustMatch)
|
||||
|
||||
// Try to set our base URI. If that fails, try to set base URI to null
|
||||
nsresult rv = aDocument->SetBaseURI(newBaseURI);
|
||||
aDocument->SetChromeXHRDocBaseURI(newBaseURI);
|
||||
aDocument->SetChromeXHRDocBaseURI(nullptr);
|
||||
if (NS_FAILED(rv)) {
|
||||
aDocument->SetBaseURI(nullptr);
|
||||
aDocument->SetChromeXHRDocBaseURI(nullptr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ interface nsIURI;
|
||||
|
||||
typedef unsigned short CSPDirective;
|
||||
|
||||
[scriptable, uuid(059b94e3-45c2-4794-ac2a-5b66a66b5967)]
|
||||
[scriptable, uuid(b622b0f8-ee51-4f7a-8c23-b3bce20e752e)]
|
||||
interface nsIContentSecurityPolicy : nsISerializable
|
||||
{
|
||||
/**
|
||||
@@ -32,24 +32,25 @@ interface nsIContentSecurityPolicy : nsISerializable
|
||||
* NOTE: When implementing a new directive, you will need to add it here but also
|
||||
* add it to the CSPStrDirectives array in nsCSPUtils.h.
|
||||
*/
|
||||
const unsigned short NO_DIRECTIVE = 0;
|
||||
const unsigned short DEFAULT_SRC_DIRECTIVE = 1;
|
||||
const unsigned short SCRIPT_SRC_DIRECTIVE = 2;
|
||||
const unsigned short OBJECT_SRC_DIRECTIVE = 3;
|
||||
const unsigned short STYLE_SRC_DIRECTIVE = 4;
|
||||
const unsigned short IMG_SRC_DIRECTIVE = 5;
|
||||
const unsigned short MEDIA_SRC_DIRECTIVE = 6;
|
||||
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 CHILD_SRC_DIRECTIVE = 17;
|
||||
const unsigned short NO_DIRECTIVE = 0;
|
||||
const unsigned short DEFAULT_SRC_DIRECTIVE = 1;
|
||||
const unsigned short SCRIPT_SRC_DIRECTIVE = 2;
|
||||
const unsigned short OBJECT_SRC_DIRECTIVE = 3;
|
||||
const unsigned short STYLE_SRC_DIRECTIVE = 4;
|
||||
const unsigned short IMG_SRC_DIRECTIVE = 5;
|
||||
const unsigned short MEDIA_SRC_DIRECTIVE = 6;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Accessor method for a read-only string version of the policy at a given
|
||||
@@ -63,6 +64,13 @@ interface nsIContentSecurityPolicy : nsISerializable
|
||||
*/
|
||||
readonly attribute unsigned long policyCount;
|
||||
|
||||
/**
|
||||
* Returns whether this policy uses the directive upgrade-insecure-requests.
|
||||
* Please note that upgrade-insecure-reqeusts also applies if the parent or
|
||||
* including document (context) makes use of the directive.
|
||||
*/
|
||||
readonly attribute bool upgradeInsecureRequests;
|
||||
|
||||
/**
|
||||
* Obtains the referrer policy (as integer) for this browsing context as
|
||||
* specified in CSP. If there are multiple policies and...
|
||||
|
||||
@@ -29,6 +29,13 @@ couldNotProcessUnknownDirective = Couldn't process unknown directive '%1$S'
|
||||
# LOCALIZATION NOTE (ignoringUnknownOption):
|
||||
# %1$S is the option that could not be understood
|
||||
ignoringUnknownOption = Ignoring unknown option %1$S
|
||||
# LOCALIZATION NOTE (ignoringDuplicateSrc):
|
||||
# %1$S defines the duplicate src
|
||||
ignoringDuplicateSrc = Ignoring duplicate source %1$S
|
||||
# LOCALIZATION NOTE (ignoringSrcWithinScriptSrc):
|
||||
# %1$S is the ignored src
|
||||
# script-src is a directive name and should not be localized
|
||||
ignoringSrcWithinScriptSrc = Ignoring "%1$S" within script-src: nonce-source or hash-source specified
|
||||
# LOCALIZATION NOTE (reportURInotHttpsOrHttp2):
|
||||
# %1$S is the ETLD of the report URI that is not HTTP or HTTPS
|
||||
reportURInotHttpsOrHttp2 = The report URI (%1$S) should be an HTTP or HTTPS URI.
|
||||
@@ -47,6 +54,11 @@ inlineStyleBlocked = An attempt to apply inline style sheets has been blocked
|
||||
# LOCALIZATION NOTE (scriptFromStringBlocked):
|
||||
# eval is a name and should not be localized.
|
||||
scriptFromStringBlocked = An attempt to call JavaScript from a string (by calling a function like eval) has been blocked
|
||||
# LOCALIZATION NOTE (upgradeInsecureRequest):
|
||||
# %1$S is the URL of the upgraded request; %2$S is the upgraded scheme.
|
||||
upgradeInsecureRequest = Upgrading insecure request '%1$S' to use '%2$S'
|
||||
# LOCALIZATION NOTE (ignoreSrcForDirective):
|
||||
ignoreSrcForDirective = Ignoring srcs for directive '%1$S'
|
||||
# LOCALIZATION NOTE (hostNameMightBeKeyword):
|
||||
# %1$S is the hostname in question and %2$S is the keyword
|
||||
hostNameMightBeKeyword = Interpreting %1$S as a hostname, not a keyword. If you intended this to be a keyword, use '%2$S' (wrapped in single quotes).
|
||||
|
||||
@@ -819,6 +819,73 @@ nsCORSListenerProxy::OnRedirectVerifyCallback(nsresult result)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Please note that the CSP directive 'upgrade-insecure-requests' relies
|
||||
// on the promise that channels get updated from http: to https: before
|
||||
// the channel fetches any data from the netwerk. Such channels should
|
||||
// not be blocked by CORS and marked as cross origin requests. E.g.:
|
||||
// toplevel page: https://www.example.com loads
|
||||
// xhr: http://www.example.com/foo which gets updated to
|
||||
// https://www.example.com/foo
|
||||
// In such a case we should bail out of CORS and rely on the promise that
|
||||
// nsHttpChannel::Connect() upgrades the request from http to https.
|
||||
bool
|
||||
CheckUpgradeInsecureRequestsPreventsCORS(nsIPrincipal* aRequestingPrincipal,
|
||||
nsIChannel* aChannel)
|
||||
{
|
||||
nsCOMPtr<nsIURI> channelURI;
|
||||
nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(channelURI));
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
bool isHttpScheme = false;
|
||||
rv = channelURI->SchemeIs("http", &isHttpScheme);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
// upgrade insecure requests is only applicable to http requests
|
||||
if (!isHttpScheme) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> principalURI;
|
||||
rv = aRequestingPrincipal->GetURI(getter_AddRefs(principalURI));
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
// if the requestingPrincipal does not have a uri, there is nothing to do
|
||||
if (!principalURI) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI>originalURI;
|
||||
rv = aChannel->GetOriginalURI(getter_AddRefs(originalURI));
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
nsAutoCString principalHost, channelHost, origChannelHost;
|
||||
|
||||
// if we can not query a host from the uri, there is nothing to do
|
||||
if (NS_FAILED(principalURI->GetAsciiHost(principalHost)) ||
|
||||
NS_FAILED(channelURI->GetAsciiHost(channelHost)) ||
|
||||
NS_FAILED(originalURI->GetAsciiHost(origChannelHost))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// if the hosts do not match, there is nothing to do
|
||||
if (!principalHost.EqualsIgnoreCase(channelHost.get())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// also check that uri matches the one of the originalURI
|
||||
if (!channelHost.EqualsIgnoreCase(origChannelHost.get())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsILoadInfo> loadInfo;
|
||||
rv = aChannel->GetLoadInfo(getter_AddRefs(loadInfo));
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
// lets see if the loadInfo indicates that the request will
|
||||
// be upgraded before fetching any data from the netwerk.
|
||||
return loadInfo->GetUpgradeInsecureRequests();
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsCORSListenerProxy::UpdateChannel(nsIChannel* aChannel,
|
||||
DataURIHandling aAllowDataURI)
|
||||
@@ -876,6 +943,17 @@ nsCORSListenerProxy::UpdateChannel(nsIChannel* aChannel,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// if the CSP directive 'upgrade-insecure-requests' is used then we should
|
||||
// not incorrectly require CORS if the only difference of a subresource
|
||||
// request and the main page is the scheme.
|
||||
// e.g. toplevel page: https://www.example.com loads
|
||||
// xhr: http://www.example.com/somefoo,
|
||||
// then the xhr request will be upgraded to https before it fetches any data
|
||||
// from the netwerk, hence we shouldn't require CORS in that specific case.
|
||||
if (CheckUpgradeInsecureRequestsPreventsCORS(mRequestingPrincipal, aChannel)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// It's a cross site load
|
||||
mHasBeenCrossSite = true;
|
||||
|
||||
|
||||
@@ -83,6 +83,10 @@ private:
|
||||
nsCOMPtr<nsINetworkInterceptController> mInterceptController;
|
||||
bool mWithCredentials;
|
||||
bool mRequestApproved;
|
||||
// Please note that the member variable mHasBeenCrossSite may rely on the
|
||||
// promise that the CSP directive 'upgrade-insecure-requests' upgrades
|
||||
// an http: request to https: in nsHttpChannel::Connect() and hence
|
||||
// a request might not be marked as cross site request based on that promise.
|
||||
bool mHasBeenCrossSite;
|
||||
bool mIsPreflight;
|
||||
#ifdef DEBUG
|
||||
|
||||
@@ -318,6 +318,19 @@ nsCSPContext::GetPolicyCount(uint32_t *outPolicyCount)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCSPContext::GetUpgradeInsecureRequests(bool *outUpgradeRequest)
|
||||
{
|
||||
*outUpgradeRequest = false;
|
||||
for (uint32_t i = 0; i < mPolicies.Length(); i++) {
|
||||
if (mPolicies[i]->hasDirective(nsIContentSecurityPolicy::UPGRADE_IF_INSECURE_DIRECTIVE)) {
|
||||
*outUpgradeRequest = true;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCSPContext::GetReferrerPolicy(uint32_t* outPolicy, bool* outIsSet)
|
||||
{
|
||||
|
||||
@@ -123,7 +123,9 @@ nsCSPTokenizer::tokenizeCSPPolicy(const nsAString &aPolicyString,
|
||||
nsCSPParser::nsCSPParser(cspTokens& aTokens,
|
||||
nsIURI* aSelfURI,
|
||||
uint64_t aInnerWindowID)
|
||||
: mTokens(aTokens)
|
||||
: mHasHashOrNonce(false)
|
||||
, mUnsafeInlineKeywordSrc(nullptr)
|
||||
, mTokens(aTokens)
|
||||
, mSelfURI(aSelfURI)
|
||||
, mInnerWindowID(aInnerWindowID)
|
||||
{
|
||||
@@ -570,8 +572,22 @@ nsCSPParser::keywordSource()
|
||||
return CSP_CreateHostSrcFromURI(mSelfURI);
|
||||
}
|
||||
|
||||
if (CSP_IsKeyword(mCurToken, CSP_UNSAFE_INLINE) ||
|
||||
CSP_IsKeyword(mCurToken, CSP_UNSAFE_EVAL)) {
|
||||
if (CSP_IsKeyword(mCurToken, CSP_UNSAFE_INLINE)) {
|
||||
// make sure script-src only contains 'unsafe-inline' once;
|
||||
// ignore duplicates and log warning
|
||||
if (mUnsafeInlineKeywordSrc) {
|
||||
const char16_t* params[] = { mCurToken.get() };
|
||||
logWarningErrorToConsole(nsIScriptError::warningFlag, "ignoringDuplicateSrc",
|
||||
params, ArrayLength(params));
|
||||
return nullptr;
|
||||
}
|
||||
// cache if we encounter 'unsafe-inline' so we can invalidate (ignore) it in
|
||||
// case that script-src directive also contains hash- or nonce-.
|
||||
mUnsafeInlineKeywordSrc = new nsCSPKeywordSrc(CSP_KeywordToEnum(mCurToken));
|
||||
return mUnsafeInlineKeywordSrc;
|
||||
}
|
||||
|
||||
if (CSP_IsKeyword(mCurToken, CSP_UNSAFE_EVAL)) {
|
||||
return new nsCSPKeywordSrc(CSP_KeywordToEnum(mCurToken));
|
||||
}
|
||||
return nullptr;
|
||||
@@ -676,6 +692,8 @@ nsCSPParser::nonceSource()
|
||||
if (dashIndex < 0) {
|
||||
return nullptr;
|
||||
}
|
||||
// cache if encountering hash or nonce to invalidate unsafe-inline
|
||||
mHasHashOrNonce = true;
|
||||
return new nsCSPNonceSrc(Substring(expr,
|
||||
dashIndex + 1,
|
||||
expr.Length() - dashIndex + 1));
|
||||
@@ -708,6 +726,8 @@ nsCSPParser::hashSource()
|
||||
|
||||
for (uint32_t i = 0; i < kHashSourceValidFnsLen; i++) {
|
||||
if (algo.LowerCaseEqualsASCII(kHashSourceValidFns[i])) {
|
||||
// cache if encountering hash or nonce to invalidate unsafe-inline
|
||||
mHasHashOrNonce = true;
|
||||
return new nsCSPHashSrc(algo, hash);
|
||||
}
|
||||
}
|
||||
@@ -784,10 +804,7 @@ nsCSPParser::sourceExpression()
|
||||
resetCurValue();
|
||||
|
||||
// If mCurToken does not provide a scheme (scheme-less source), we apply the scheme
|
||||
// from selfURI but we also need to remember if the protected resource is http, in
|
||||
// which case we should allow https loads, see:
|
||||
// http://www.w3.org/TR/CSP2/#match-source-expression
|
||||
bool allowHttps = false;
|
||||
// from selfURI
|
||||
if (parsedScheme.IsEmpty()) {
|
||||
// Resetting internal helpers, because we might already have parsed some of the host
|
||||
// when trying to parse a scheme.
|
||||
@@ -795,14 +812,13 @@ nsCSPParser::sourceExpression()
|
||||
nsAutoCString selfScheme;
|
||||
mSelfURI->GetScheme(selfScheme);
|
||||
parsedScheme.AssignASCII(selfScheme.get());
|
||||
allowHttps = selfScheme.EqualsASCII("http");
|
||||
}
|
||||
|
||||
// At this point we are expecting a host to be parsed.
|
||||
// Trying to create a new nsCSPHost.
|
||||
if (nsCSPHostSrc *cspHost = hostSource()) {
|
||||
// Do not forget to set the parsed scheme.
|
||||
cspHost->setScheme(parsedScheme, allowHttps);
|
||||
cspHost->setScheme(parsedScheme);
|
||||
return cspHost;
|
||||
}
|
||||
// Error was reported in hostSource()
|
||||
@@ -968,6 +984,12 @@ nsCSPParser::directiveName()
|
||||
params, ArrayLength(params));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// special case handling for upgrade-insecure-requests
|
||||
if (CSP_IsDirective(mCurToken, nsIContentSecurityPolicy::UPGRADE_IF_INSECURE_DIRECTIVE)) {
|
||||
return new nsUpgradeInsecureDirective(CSP_StringToCSPDirective(mCurToken));
|
||||
}
|
||||
|
||||
return new nsCSPDirective(CSP_StringToCSPDirective(mCurToken));
|
||||
}
|
||||
|
||||
@@ -1006,6 +1028,25 @@ nsCSPParser::directive()
|
||||
return;
|
||||
}
|
||||
|
||||
// special case handling for upgrade-insecure-requests, which is only specified
|
||||
// by a directive name but does not include any srcs.
|
||||
if (cspDir->equals(nsIContentSecurityPolicy::UPGRADE_IF_INSECURE_DIRECTIVE)) {
|
||||
if (mCurDir.Length() > 1) {
|
||||
const char16_t* params[] = { NS_LITERAL_STRING("upgrade-insecure-requests").get() };
|
||||
logWarningErrorToConsole(nsIScriptError::warningFlag,
|
||||
"ignoreSrcForDirective",
|
||||
params, ArrayLength(params));
|
||||
}
|
||||
// add the directive and return
|
||||
mPolicy->addUpgradeInsecDir(static_cast<nsUpgradeInsecureDirective*>(cspDir));
|
||||
return;
|
||||
}
|
||||
|
||||
// make sure to reset cache variables when trying to invalidate unsafe-inline;
|
||||
// unsafe-inline might not only appear in script-src, but also in default-src
|
||||
mHasHashOrNonce = false;
|
||||
mUnsafeInlineKeywordSrc = nullptr;
|
||||
|
||||
// Try to parse all the srcs by handing the array off to directiveValue
|
||||
nsTArray<nsCSPBaseSrc*> srcs;
|
||||
directiveValue(srcs);
|
||||
@@ -1017,6 +1058,18 @@ nsCSPParser::directive()
|
||||
srcs.AppendElement(keyword);
|
||||
}
|
||||
|
||||
// if a hash or nonce is specified within script-src, then
|
||||
// unsafe-inline should be ignored, see:
|
||||
// http://www.w3.org/TR/CSP2/#directive-script-src
|
||||
if (cspDir->equals(nsIContentSecurityPolicy::SCRIPT_SRC_DIRECTIVE) &&
|
||||
mHasHashOrNonce && mUnsafeInlineKeywordSrc) {
|
||||
mUnsafeInlineKeywordSrc->invalidate();
|
||||
// log to the console that unsafe-inline will be ignored
|
||||
const char16_t* params[] = { NS_LITERAL_STRING("'unsafe-inline'").get() };
|
||||
logWarningErrorToConsole(nsIScriptError::warningFlag, "ignoringSrcWithinScriptSrc",
|
||||
params, ArrayLength(params));
|
||||
}
|
||||
|
||||
// Add the newly created srcs to the directive and add the directive to the policy
|
||||
cspDir->addSrcs(srcs);
|
||||
mPolicy->addDirective(cspDir);
|
||||
|
||||
@@ -229,6 +229,10 @@ class nsCSPParser {
|
||||
nsString mCurToken;
|
||||
nsTArray<nsString> mCurDir;
|
||||
|
||||
// cache variables to ignore unsafe-inline if hash or nonce is specified
|
||||
bool mHasHashOrNonce; // false, if no hash or nonce is defined
|
||||
nsCSPKeywordSrc* mUnsafeInlineKeywordSrc; // null, otherwise invlidate()
|
||||
|
||||
cspTokens mTokens;
|
||||
nsIURI* mSelfURI;
|
||||
nsCSPPolicy* mPolicy;
|
||||
|
||||
+117
-44
@@ -257,6 +257,59 @@ CSP_IsQuotelessKeyword(const nsAString& aKey)
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks whether the current directive permits a specific
|
||||
* scheme. This function is called from nsCSPSchemeSrc() and
|
||||
* also nsCSPHostSrc.
|
||||
* @param aEnforcementScheme
|
||||
* The scheme that this directive allows
|
||||
* @param aUri
|
||||
* The uri of the subresource load.
|
||||
* @param aReportOnly
|
||||
* Whether the enforced policy is report only or not.
|
||||
* @param aUpgradeInsecure
|
||||
* Whether the policy makes use of the directive
|
||||
* 'upgrade-insecure-requests'.
|
||||
*/
|
||||
|
||||
bool
|
||||
permitsScheme(const nsAString& aEnforcementScheme,
|
||||
nsIURI* aUri,
|
||||
bool aReportOnly,
|
||||
bool aUpgradeInsecure)
|
||||
{
|
||||
nsAutoCString scheme;
|
||||
nsresult rv = aUri->GetScheme(scheme);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
// no scheme to enforce, let's allow the load (e.g. script-src *)
|
||||
if (aEnforcementScheme.IsEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// if the scheme matches, all good - allow the load
|
||||
if (aEnforcementScheme.EqualsASCII(scheme.get())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// allow scheme-less sources where the protected resource is http
|
||||
// and the load is https, see:
|
||||
// http://www.w3.org/TR/CSP2/#match-source-expression
|
||||
if (aEnforcementScheme.EqualsASCII("http") &&
|
||||
scheme.EqualsASCII("https")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Allow the load when enforcing upgrade-insecure-requests with the
|
||||
// promise the request gets upgraded from http to https and ws to wss.
|
||||
// See nsHttpChannel::Connect() and also WebSocket.cpp. Please note,
|
||||
// the report only policies should not allow the load and report
|
||||
// the error back to the page.
|
||||
return ((aUpgradeInsecure && !aReportOnly) &&
|
||||
((scheme.EqualsASCII("http") && aEnforcementScheme.EqualsASCII("https")) ||
|
||||
(scheme.EqualsASCII("ws") && aEnforcementScheme.EqualsASCII("wss"))));
|
||||
}
|
||||
|
||||
/* ===== nsCSPSrc ============================ */
|
||||
|
||||
nsCSPBaseSrc::nsCSPBaseSrc()
|
||||
@@ -271,7 +324,8 @@ nsCSPBaseSrc::~nsCSPBaseSrc()
|
||||
// nsCSPKeywordSrc and nsCSPHashSource fall back to this base class
|
||||
// implementation which will never allow the load.
|
||||
bool
|
||||
nsCSPBaseSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected) const
|
||||
nsCSPBaseSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
|
||||
bool aReportOnly, bool aUpgradeInsecure) const
|
||||
{
|
||||
if (CSPUTILSLOGENABLED()) {
|
||||
nsAutoCString spec;
|
||||
@@ -306,19 +360,16 @@ nsCSPSchemeSrc::~nsCSPSchemeSrc()
|
||||
}
|
||||
|
||||
bool
|
||||
nsCSPSchemeSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected) const
|
||||
nsCSPSchemeSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
|
||||
bool aReportOnly, bool aUpgradeInsecure) const
|
||||
{
|
||||
if (CSPUTILSLOGENABLED()) {
|
||||
nsAutoCString spec;
|
||||
aUri->GetSpec(spec);
|
||||
CSPUTILSLOG(("nsCSPSchemeSrc::permits, aUri: %s", spec.get()));
|
||||
}
|
||||
|
||||
NS_ASSERTION((!mScheme.EqualsASCII("")), "scheme can not be the empty string");
|
||||
nsAutoCString scheme;
|
||||
nsresult rv = aUri->GetScheme(scheme);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
return mScheme.EqualsASCII(scheme.get());
|
||||
MOZ_ASSERT((!mScheme.EqualsASCII("")), "scheme can not be the empty string");
|
||||
return permitsScheme(mScheme, aUri, aReportOnly, aUpgradeInsecure);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -332,7 +383,6 @@ nsCSPSchemeSrc::toString(nsAString& outStr) const
|
||||
|
||||
nsCSPHostSrc::nsCSPHostSrc(const nsAString& aHost)
|
||||
: mHost(aHost)
|
||||
, mAllowHttps(false)
|
||||
{
|
||||
ToLowerCase(mHost);
|
||||
}
|
||||
@@ -425,7 +475,8 @@ permitsPort(const nsAString& aEnforcementScheme,
|
||||
}
|
||||
|
||||
bool
|
||||
nsCSPHostSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected) const
|
||||
nsCSPHostSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
|
||||
bool aReportOnly, bool aUpgradeInsecure) const
|
||||
{
|
||||
if (CSPUTILSLOGENABLED()) {
|
||||
nsAutoCString spec;
|
||||
@@ -437,21 +488,8 @@ nsCSPHostSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected
|
||||
// http://www.w3.org/TR/CSP11/#match-source-expression
|
||||
|
||||
// 4.3) scheme matching: Check if the scheme matches.
|
||||
nsAutoCString scheme;
|
||||
nsresult rv = aUri->GetScheme(scheme);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
if (!mScheme.IsEmpty() &&
|
||||
!mScheme.EqualsASCII(scheme.get())) {
|
||||
|
||||
// We should not return false for scheme-less sources where the protected resource
|
||||
// is http and the load is https, see:
|
||||
// http://www.w3.org/TR/CSP2/#match-source-expression
|
||||
bool isHttpsScheme =
|
||||
(NS_SUCCEEDED(aUri->SchemeIs("https", &isHttpsScheme)) && isHttpsScheme);
|
||||
|
||||
if (!(isHttpsScheme && mAllowHttps)) {
|
||||
return false;
|
||||
}
|
||||
if (!permitsScheme(mScheme, aUri, aReportOnly, aUpgradeInsecure)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The host in nsCSpHostSrc should never be empty. In case we are enforcing
|
||||
@@ -466,7 +504,7 @@ nsCSPHostSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected
|
||||
// Before we can check if the host matches, we have to
|
||||
// extract the host part from aUri.
|
||||
nsAutoCString uriHost;
|
||||
rv = aUri->GetHost(uriHost);
|
||||
nsresult rv = aUri->GetHost(uriHost);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
// 4.5) host matching: Check if the allowed host starts with a wilcard.
|
||||
@@ -556,11 +594,10 @@ nsCSPHostSrc::toString(nsAString& outStr) const
|
||||
}
|
||||
|
||||
void
|
||||
nsCSPHostSrc::setScheme(const nsAString& aScheme, bool aAllowHttps)
|
||||
nsCSPHostSrc::setScheme(const nsAString& aScheme)
|
||||
{
|
||||
mScheme = aScheme;
|
||||
ToLowerCase(mScheme);
|
||||
mAllowHttps = aAllowHttps;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -578,10 +615,11 @@ nsCSPHostSrc::appendPath(const nsAString& aPath)
|
||||
/* ===== nsCSPKeywordSrc ===================== */
|
||||
|
||||
nsCSPKeywordSrc::nsCSPKeywordSrc(enum CSPKeyword aKeyword)
|
||||
: mKeyword(aKeyword)
|
||||
, mInvalidated(false)
|
||||
{
|
||||
NS_ASSERTION((aKeyword != CSP_SELF),
|
||||
"'self' should have been replaced in the parser");
|
||||
mKeyword = aKeyword;
|
||||
}
|
||||
|
||||
nsCSPKeywordSrc::~nsCSPKeywordSrc()
|
||||
@@ -591,8 +629,16 @@ nsCSPKeywordSrc::~nsCSPKeywordSrc()
|
||||
bool
|
||||
nsCSPKeywordSrc::allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce) const
|
||||
{
|
||||
CSPUTILSLOG(("nsCSPKeywordSrc::allows, aKeyWord: %s, a HashOrNonce: %s",
|
||||
CSP_EnumToKeyword(aKeyword), NS_ConvertUTF16toUTF8(aHashOrNonce).get()));
|
||||
CSPUTILSLOG(("nsCSPKeywordSrc::allows, aKeyWord: %s, aHashOrNonce: %s, mInvalidated: %s",
|
||||
CSP_EnumToKeyword(aKeyword),
|
||||
NS_ConvertUTF16toUTF8(aHashOrNonce).get(),
|
||||
mInvalidated ? "yes" : "false"));
|
||||
// if unsafe-inline should be ignored, then bail early
|
||||
if (mInvalidated) {
|
||||
NS_ASSERTION(mKeyword == CSP_UNSAFE_INLINE,
|
||||
"should only invalidate unsafe-inline within script-src");
|
||||
return false;
|
||||
}
|
||||
return mKeyword == aKeyword;
|
||||
}
|
||||
|
||||
@@ -602,6 +648,14 @@ nsCSPKeywordSrc::toString(nsAString& outStr) const
|
||||
outStr.AppendASCII(CSP_EnumToKeyword(mKeyword));
|
||||
}
|
||||
|
||||
void
|
||||
nsCSPKeywordSrc::invalidate()
|
||||
{
|
||||
mInvalidated = true;
|
||||
NS_ASSERTION(mInvalidated == CSP_UNSAFE_INLINE,
|
||||
"invalidate 'unsafe-inline' only within script-src");
|
||||
}
|
||||
|
||||
/* ===== nsCSPNonceSrc ==================== */
|
||||
|
||||
nsCSPNonceSrc::nsCSPNonceSrc(const nsAString& aNonce)
|
||||
@@ -614,7 +668,8 @@ nsCSPNonceSrc::~nsCSPNonceSrc()
|
||||
}
|
||||
|
||||
bool
|
||||
nsCSPNonceSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected) const
|
||||
nsCSPNonceSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
|
||||
bool aReportOnly, bool aUpgradeInsecure) const
|
||||
{
|
||||
if (CSPUTILSLOGENABLED()) {
|
||||
nsAutoCString spec;
|
||||
@@ -742,7 +797,8 @@ nsCSPDirective::~nsCSPDirective()
|
||||
}
|
||||
|
||||
bool
|
||||
nsCSPDirective::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected) const
|
||||
nsCSPDirective::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
|
||||
bool aReportOnly, bool aUpgradeInsecure) const
|
||||
{
|
||||
if (CSPUTILSLOGENABLED()) {
|
||||
nsAutoCString spec;
|
||||
@@ -751,20 +807,13 @@ nsCSPDirective::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirect
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < mSrcs.Length(); i++) {
|
||||
if (mSrcs[i]->permits(aUri, aNonce, aWasRedirected)) {
|
||||
if (mSrcs[i]->permits(aUri, aNonce, aWasRedirected, aReportOnly, aUpgradeInsecure)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
nsCSPDirective::permits(nsIURI* aUri) const
|
||||
{
|
||||
nsString dummyNonce;
|
||||
return permits(aUri, dummyNonce, false);
|
||||
}
|
||||
|
||||
bool
|
||||
nsCSPDirective::allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce) const
|
||||
{
|
||||
@@ -879,6 +928,11 @@ nsCSPDirective::toDomCSPStruct(mozilla::dom::CSP& outCSP) const
|
||||
outCSP.mForm_action.Value() = mozilla::Move(srcs);
|
||||
return;
|
||||
|
||||
case nsIContentSecurityPolicy::UPGRADE_IF_INSECURE_DIRECTIVE:
|
||||
outCSP.mUpgrade_insecure_requests.Construct();
|
||||
// does not have any srcs
|
||||
return;
|
||||
|
||||
// REFERRER_DIRECTIVE is handled in nsCSPPolicy::toDomCSPStruct()
|
||||
|
||||
default:
|
||||
@@ -911,10 +965,29 @@ nsCSPDirective::getReportURIs(nsTArray<nsString> &outReportURIs) const
|
||||
}
|
||||
}
|
||||
|
||||
/* =============== nsUpgradeInsecureDirective ============= */
|
||||
|
||||
nsUpgradeInsecureDirective::nsUpgradeInsecureDirective(CSPDirective aDirective)
|
||||
: nsCSPDirective(aDirective)
|
||||
{
|
||||
}
|
||||
|
||||
nsUpgradeInsecureDirective::~nsUpgradeInsecureDirective()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
nsUpgradeInsecureDirective::toString(nsAString& outStr) const
|
||||
{
|
||||
outStr.AppendASCII(CSP_CSPDirectiveToString(
|
||||
nsIContentSecurityPolicy::UPGRADE_IF_INSECURE_DIRECTIVE));
|
||||
}
|
||||
|
||||
/* ===== nsCSPPolicy ========================= */
|
||||
|
||||
nsCSPPolicy::nsCSPPolicy()
|
||||
: mReportOnly(false)
|
||||
: mUpgradeInsecDir(nullptr)
|
||||
, mReportOnly(false)
|
||||
{
|
||||
CSPUTILSLOG(("nsCSPPolicy::nsCSPPolicy"));
|
||||
}
|
||||
@@ -960,7 +1033,7 @@ nsCSPPolicy::permits(CSPDirective aDir,
|
||||
// These directive arrays are short (1-5 elements), not worth using a hashtable.
|
||||
for (uint32_t i = 0; i < mDirectives.Length(); i++) {
|
||||
if (mDirectives[i]->equals(aDir)) {
|
||||
if (!mDirectives[i]->permits(aUri, aNonce, aWasRedirected)) {
|
||||
if (!mDirectives[i]->permits(aUri, aNonce, aWasRedirected, mReportOnly, mUpgradeInsecDir)) {
|
||||
mDirectives[i]->toString(outViolatedDirective);
|
||||
return false;
|
||||
}
|
||||
@@ -974,7 +1047,7 @@ nsCSPPolicy::permits(CSPDirective aDir,
|
||||
// If the above loop runs through, we haven't found a matching directive.
|
||||
// Avoid relooping, just store the result of default-src while looping.
|
||||
if (!aSpecific && defaultDir) {
|
||||
if (!defaultDir->permits(aUri, aNonce, aWasRedirected)) {
|
||||
if (!defaultDir->permits(aUri, aNonce, aWasRedirected, mReportOnly, mUpgradeInsecDir)) {
|
||||
defaultDir->toString(outViolatedDirective);
|
||||
return false;
|
||||
}
|
||||
|
||||
+98
-33
@@ -70,24 +70,25 @@ void CSP_LogMessage(const nsAString& aMessage,
|
||||
// Order of elements below important! Make sure it matches the order as in
|
||||
// nsIContentSecurityPolicy.idl
|
||||
static const char* CSPStrDirectives[] = {
|
||||
"-error-", // NO_DIRECTIVE
|
||||
"default-src", // DEFAULT_SRC_DIRECTIVE
|
||||
"script-src", // SCRIPT_SRC_DIRECTIVE
|
||||
"object-src", // OBJECT_SRC_DIRECTIVE
|
||||
"style-src", // STYLE_SRC_DIRECTIVE
|
||||
"img-src", // IMG_SRC_DIRECTIVE
|
||||
"media-src", // MEDIA_SRC_DIRECTIVE
|
||||
"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
|
||||
"child-src" // CHILD_SRC_DIRECTIVE
|
||||
"-error-", // NO_DIRECTIVE
|
||||
"default-src", // DEFAULT_SRC_DIRECTIVE
|
||||
"script-src", // SCRIPT_SRC_DIRECTIVE
|
||||
"object-src", // OBJECT_SRC_DIRECTIVE
|
||||
"style-src", // STYLE_SRC_DIRECTIVE
|
||||
"img-src", // IMG_SRC_DIRECTIVE
|
||||
"media-src", // MEDIA_SRC_DIRECTIVE
|
||||
"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
|
||||
};
|
||||
|
||||
inline const char* CSP_CSPDirectiveToString(CSPDirective aDir)
|
||||
@@ -183,7 +184,8 @@ class nsCSPBaseSrc {
|
||||
nsCSPBaseSrc();
|
||||
virtual ~nsCSPBaseSrc();
|
||||
|
||||
virtual bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected) const;
|
||||
virtual bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
|
||||
bool aReportOnly, bool aUpgradeInsecure) const;
|
||||
virtual bool allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce) const;
|
||||
virtual void toString(nsAString& outStr) const = 0;
|
||||
};
|
||||
@@ -195,7 +197,8 @@ class nsCSPSchemeSrc : public nsCSPBaseSrc {
|
||||
explicit nsCSPSchemeSrc(const nsAString& aScheme);
|
||||
virtual ~nsCSPSchemeSrc();
|
||||
|
||||
bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected) const;
|
||||
bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
|
||||
bool aReportOnly, bool aUpgradeInsecure) const;
|
||||
void toString(nsAString& outStr) const;
|
||||
|
||||
private:
|
||||
@@ -209,10 +212,11 @@ class nsCSPHostSrc : public nsCSPBaseSrc {
|
||||
explicit nsCSPHostSrc(const nsAString& aHost);
|
||||
virtual ~nsCSPHostSrc();
|
||||
|
||||
bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected) const;
|
||||
bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
|
||||
bool aReportOnly, bool aUpgradeInsecure) const;
|
||||
void toString(nsAString& outStr) const;
|
||||
|
||||
void setScheme(const nsAString& aScheme, bool aAllowHttps = false);
|
||||
void setScheme(const nsAString& aScheme);
|
||||
void setPort(const nsAString& aPort);
|
||||
void appendPath(const nsAString &aPath);
|
||||
|
||||
@@ -221,7 +225,6 @@ class nsCSPHostSrc : public nsCSPBaseSrc {
|
||||
nsString mHost;
|
||||
nsString mPort;
|
||||
nsString mPath;
|
||||
bool mAllowHttps;
|
||||
};
|
||||
|
||||
/* =============== nsCSPKeywordSrc ============ */
|
||||
@@ -233,9 +236,12 @@ class nsCSPKeywordSrc : public nsCSPBaseSrc {
|
||||
|
||||
bool allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce) const;
|
||||
void toString(nsAString& outStr) const;
|
||||
void invalidate();
|
||||
|
||||
private:
|
||||
CSPKeyword mKeyword;
|
||||
// invalidate 'unsafe-inline' if nonce- or hash-source specified
|
||||
bool mInvalidated;
|
||||
};
|
||||
|
||||
/* =============== nsCSPNonceSource =========== */
|
||||
@@ -245,7 +251,8 @@ class nsCSPNonceSrc : public nsCSPBaseSrc {
|
||||
explicit nsCSPNonceSrc(const nsAString& aNonce);
|
||||
virtual ~nsCSPNonceSrc();
|
||||
|
||||
bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected) const;
|
||||
bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
|
||||
bool aReportOnly, bool aUpgradeInsecure) const;
|
||||
bool allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce) const;
|
||||
void toString(nsAString& outStr) const;
|
||||
|
||||
@@ -285,17 +292,16 @@ class nsCSPReportURI : public nsCSPBaseSrc {
|
||||
|
||||
class nsCSPDirective {
|
||||
public:
|
||||
nsCSPDirective();
|
||||
explicit nsCSPDirective(CSPDirective aDirective);
|
||||
virtual ~nsCSPDirective();
|
||||
|
||||
bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected) const;
|
||||
bool permits(nsIURI* aUri) const;
|
||||
bool allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce) const;
|
||||
void toString(nsAString& outStr) const;
|
||||
virtual bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
|
||||
bool aReportOnly, bool aUpgradeInsecure) const;
|
||||
virtual bool allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce) const;
|
||||
virtual void toString(nsAString& outStr) const;
|
||||
void toDomCSPStruct(mozilla::dom::CSP& outCSP) const;
|
||||
|
||||
inline void addSrcs(const nsTArray<nsCSPBaseSrc*>& aSrcs)
|
||||
virtual void addSrcs(const nsTArray<nsCSPBaseSrc*>& aSrcs)
|
||||
{ mSrcs = aSrcs; }
|
||||
|
||||
bool restrictsContentType(nsContentPolicyType aContentType) const;
|
||||
@@ -313,6 +319,58 @@ class nsCSPDirective {
|
||||
nsTArray<nsCSPBaseSrc*> mSrcs;
|
||||
};
|
||||
|
||||
/* =============== nsUpgradeInsecureDirective === */
|
||||
|
||||
/*
|
||||
* Upgrading insecure requests includes the following actors:
|
||||
* (1) CSP:
|
||||
* The CSP implementation whitelists the http-request
|
||||
* in case the policy is executed in enforcement mode.
|
||||
* The CSP implementation however does not allow http
|
||||
* requests to succeed if executed in report-only mode.
|
||||
* In such a case the CSP implementation reports the
|
||||
* error back to the page.
|
||||
*
|
||||
* (2) MixedContent:
|
||||
* The evalution of MixedContent whitelists all http
|
||||
* requests with the promise that the http requests
|
||||
* gets upgraded to https before any data is fetched
|
||||
* from the network.
|
||||
*
|
||||
* (3) CORS:
|
||||
* Does not consider the http request to be of a
|
||||
* different origin in case the scheme is the only
|
||||
* difference in otherwise matching URIs.
|
||||
*
|
||||
* (4) nsHttpChannel:
|
||||
* Before connecting, the channel gets redirected
|
||||
* to use https.
|
||||
*
|
||||
* (5) WebSocketChannel:
|
||||
* Similar to the httpChannel, the websocketchannel
|
||||
* gets upgraded from ws to wss.
|
||||
*/
|
||||
class nsUpgradeInsecureDirective : public nsCSPDirective {
|
||||
public:
|
||||
explicit nsUpgradeInsecureDirective(CSPDirective aDirective);
|
||||
~nsUpgradeInsecureDirective();
|
||||
|
||||
bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
|
||||
bool aReportOnly, bool aUpgradeInsecure) const
|
||||
{ return false; }
|
||||
|
||||
bool permits(nsIURI* aUri) const
|
||||
{ return false; }
|
||||
|
||||
bool allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce) const
|
||||
{ return false; }
|
||||
|
||||
void toString(nsAString& outStr) const;
|
||||
|
||||
void addSrcs(const nsTArray<nsCSPBaseSrc*>& aSrcs)
|
||||
{ MOZ_ASSERT(false, "upgrade-insecure-requests does not hold any srcs"); }
|
||||
};
|
||||
|
||||
/* =============== nsCSPPolicy ================== */
|
||||
|
||||
class nsCSPPolicy {
|
||||
@@ -340,6 +398,12 @@ class nsCSPPolicy {
|
||||
inline void addDirective(nsCSPDirective* aDir)
|
||||
{ mDirectives.AppendElement(aDir); }
|
||||
|
||||
inline void addUpgradeInsecDir(nsUpgradeInsecureDirective* aDir)
|
||||
{
|
||||
mUpgradeInsecDir = aDir;
|
||||
addDirective(aDir);
|
||||
}
|
||||
|
||||
bool hasDirective(CSPDirective aDir) const;
|
||||
|
||||
inline void setReportOnlyFlag(bool aFlag)
|
||||
@@ -365,9 +429,10 @@ class nsCSPPolicy {
|
||||
{ return mDirectives.Length(); }
|
||||
|
||||
private:
|
||||
nsTArray<nsCSPDirective*> mDirectives;
|
||||
bool mReportOnly;
|
||||
nsString mReferrerPolicy;
|
||||
nsUpgradeInsecureDirective* mUpgradeInsecDir;
|
||||
nsTArray<nsCSPDirective*> mDirectives;
|
||||
bool mReportOnly;
|
||||
nsString mReferrerPolicy;
|
||||
};
|
||||
|
||||
#endif /* nsCSPUtils_h___ */
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "nsMixedContentBlocker.h"
|
||||
|
||||
#include "nsContentPolicyUtils.h"
|
||||
#include "nsCSPContext.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsINode.h"
|
||||
#include "nsCOMPtr.h"
|
||||
@@ -594,6 +595,26 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
|
||||
// Determine if the rootDoc is https and if the user decided to allow Mixed Content
|
||||
nsCOMPtr<nsIDocShell> docShell = NS_CP_GetDocShellFromContext(aRequestingContext);
|
||||
NS_ENSURE_TRUE(docShell, NS_OK);
|
||||
|
||||
// The page might have set the CSP directive 'upgrade-insecure-requests'. In such
|
||||
// a case allow the http: load to succeed with the promise that the channel will
|
||||
// get upgraded to https before fetching any data from the netwerk.
|
||||
// Please see: nsHttpChannel::Connect()
|
||||
//
|
||||
// Please note that the CSP directive 'upgrade-insecure-requests' only applies to
|
||||
// http: and ws: (for websockets). Websockets are not subject to mixed content
|
||||
// blocking since insecure websockets are not allowed within secure pages. Hence,
|
||||
// we only have to check against http: here. Skip mixed content blocking if the
|
||||
// subresource load uses http: and the CSP directive 'upgrade-insecure-requests'
|
||||
// is present on the page.
|
||||
bool isHttpScheme = false;
|
||||
rv = aContentLocation->SchemeIs("http", &isHttpScheme);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (isHttpScheme && docShell->GetDocument()->GetUpgradeInsecureRequests()) {
|
||||
*aDecision = ACCEPT;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool rootHasSecureConnection = false;
|
||||
bool allowMixedContent = false;
|
||||
bool isRootDocShell = false;
|
||||
@@ -603,7 +624,6 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
// Get the sameTypeRoot tree item from the docshell
|
||||
nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot;
|
||||
docShell->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
|
||||
|
||||
@@ -211,7 +211,9 @@ nsresult TestDirectives() {
|
||||
{ "script-src 'nonce-correctscriptnonce'",
|
||||
"script-src 'nonce-correctscriptnonce'" },
|
||||
{ "script-src 'sha256-siVR8vAcqP06h2ppeNwqgjr0yZ6yned4X2VF84j4GmI='",
|
||||
"script-src 'sha256-siVR8vAcqP06h2ppeNwqgjr0yZ6yned4X2VF84j4GmI='" }
|
||||
"script-src 'sha256-siVR8vAcqP06h2ppeNwqgjr0yZ6yned4X2VF84j4GmI='" },
|
||||
{ "referrer no-referrer",
|
||||
"referrer no-referrer" }
|
||||
};
|
||||
|
||||
uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest);
|
||||
@@ -273,7 +275,11 @@ nsresult TestIgnoreUpperLowerCasePolicies() {
|
||||
{ "script-src 'NoncE-NONCENEEDSTOBEUPPERCASE'",
|
||||
"script-src 'nonce-NONCENEEDSTOBEUPPERCASE'" },
|
||||
{ "script-src 'SHA256-siVR8vAcqP06h2ppeNwqgjr0yZ6yned4X2VF84j4GmI='",
|
||||
"script-src 'sha256-siVR8vAcqP06h2ppeNwqgjr0yZ6yned4X2VF84j4GmI='" }
|
||||
"script-src 'sha256-siVR8vAcqP06h2ppeNwqgjr0yZ6yned4X2VF84j4GmI='" },
|
||||
{ "refERRer No-refeRRer",
|
||||
"referrer No-refeRRer" },
|
||||
{ "upgrade-INSECURE-requests",
|
||||
"upgrade-insecure-requests" }
|
||||
};
|
||||
|
||||
uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest);
|
||||
@@ -443,7 +449,11 @@ nsresult TestSimplePolicies() {
|
||||
{ "default-src -; ",
|
||||
"default-src http://-" },
|
||||
{ "script-src 1",
|
||||
"script-src http://1" }
|
||||
"script-src http://1" },
|
||||
{ "upgrade-insecure-requests",
|
||||
"upgrade-insecure-requests" },
|
||||
{ "upgrade-insecure-requests https:",
|
||||
"upgrade-insecure-requests" }
|
||||
};
|
||||
|
||||
uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest);
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Bug 1139297 - Implement CSP upgrade-insecure-requests directive</title>
|
||||
<!-- style -->
|
||||
<link rel='stylesheet' type='text/css' href='http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_server.sjs?style' media='screen' />
|
||||
|
||||
<!-- font -->
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: "foofont";
|
||||
src: url('http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_server.sjs?font');
|
||||
}
|
||||
.div_foo { font-family: "foofont"; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- images: -->
|
||||
<img src="http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_server.sjs?img"></img>
|
||||
|
||||
<!-- redirects: upgrade http:// to https:// redirect to http:// and then upgrade to https:// again -->
|
||||
<img src="http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_server.sjs?redirect-image"></img>
|
||||
|
||||
<!-- script: -->
|
||||
<script src="http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_server.sjs?script"></script>
|
||||
|
||||
<!-- media: -->
|
||||
<audio src="http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_server.sjs?media"></audio>
|
||||
|
||||
<!-- objects: -->
|
||||
<object width="10" height="10" data="http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_server.sjs?object"></object>
|
||||
|
||||
<!-- font: (apply font loaded in header to div) -->
|
||||
<div class="div_foo">foo</div>
|
||||
|
||||
<!-- iframe: (same origin) -->
|
||||
<iframe src="http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_server.sjs?iframe">
|
||||
<!-- within that iframe we load an image over http and make sure the requested gets upgraded to https -->
|
||||
</iframe>
|
||||
|
||||
<!-- xhr: -->
|
||||
<script type="application/javascript">
|
||||
var myXHR = new XMLHttpRequest();
|
||||
myXHR.open("GET", "http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_server.sjs?xhr");
|
||||
myXHR.send(null);
|
||||
</script>
|
||||
|
||||
<!-- websockets: upgrade ws:// to wss://-->
|
||||
<script type="application/javascript">
|
||||
var mySocket = new WebSocket("ws://example.com/tests/dom/security/test/csp/file_upgrade_insecure");
|
||||
mySocket.onopen = function(e) {
|
||||
if (mySocket.url.includes("wss://")) {
|
||||
window.parent.postMessage({result: "websocket-ok"}, "*");
|
||||
}
|
||||
else {
|
||||
window.parent.postMessage({result: "websocket-error"}, "*");
|
||||
}
|
||||
};
|
||||
mySocket.onerror = function(e) {
|
||||
window.parent.postMessage({result: "websocket-unexpected-error"}, "*");
|
||||
};
|
||||
</script>
|
||||
|
||||
<!-- form action: (upgrade POST from http:// to https://) -->
|
||||
<iframe name='formFrame' id='formFrame'></iframe>
|
||||
<form target="formFrame" action="http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_server.sjs?form" method="POST">
|
||||
<input name="foo" value="foo">
|
||||
<input type="submit" id="submitButton" formenctype='multipart/form-data' value="Submit form">
|
||||
</form>
|
||||
<script type="text/javascript">
|
||||
var submitButton = document.getElementById('submitButton');
|
||||
submitButton.click();
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,49 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Bug 1139297 - Implement CSP upgrade-insecure-requests directive</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
// === TEST 1
|
||||
var url1 = "http://test1.example.com/tests/dom/security/test/csp/file_upgrade_insecure_cors_server.sjs?test1";
|
||||
var xhr1 = new XMLHttpRequest();
|
||||
xhr1.open("GET", url1, true);
|
||||
xhr1.onload = function() {
|
||||
window.parent.postMessage(xhr1.response, "*");
|
||||
};
|
||||
xhr1.onerror = function() {
|
||||
window.parent.postMessage("test1-failed", "*");
|
||||
};
|
||||
xhr1.send();
|
||||
|
||||
// === TEST 2
|
||||
var url2 = "http://test1.example.com/tests/dom/security/test/csp/file_upgrade_insecure_cors_server.sjs?test2";
|
||||
var xhr2 = new XMLHttpRequest();
|
||||
xhr2.open("GET", url2, true);
|
||||
xhr2.onload = function() {
|
||||
window.parent.postMessage(xhr2.response, "*");
|
||||
};
|
||||
xhr2.onerror = function() {
|
||||
window.parent.postMessage("test2-failed", "*");
|
||||
};
|
||||
xhr2.send();
|
||||
|
||||
// === TEST 3
|
||||
var url3 = "http://test2.example.com/tests/dom/security/test/csp/file_upgrade_insecure_cors_server.sjs?test3";
|
||||
var xhr3 = new XMLHttpRequest();
|
||||
xhr3.open("GET", url3, true);
|
||||
xhr3.onload = function() {
|
||||
window.parent.postMessage(xhr3.response, "*");
|
||||
};
|
||||
xhr3.onerror = function() {
|
||||
window.parent.postMessage("test3-failed", "*");
|
||||
};
|
||||
xhr3.send();
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,62 @@
|
||||
// Custom *.sjs file specifically for the needs of Bug:
|
||||
// Bug 1139297 - Implement CSP upgrade-insecure-requests directive
|
||||
|
||||
function handleRequest(request, response)
|
||||
{
|
||||
// avoid confusing cache behaviors
|
||||
response.setHeader("Cache-Control", "no-cache", false);
|
||||
|
||||
// perform sanity check and make sure that all requests get upgraded to use https
|
||||
if (request.scheme !== "https") {
|
||||
response.write("request not https");
|
||||
return;
|
||||
}
|
||||
|
||||
var queryString = request.queryString;
|
||||
|
||||
// TEST 1
|
||||
if (queryString === "test1") {
|
||||
var newLocation =
|
||||
"http://test1.example.com/tests/dom/security/test/csp/file_upgrade_insecure_cors_server.sjs?redir-test1";
|
||||
response.setStatusLine("1.1", 302, "Found");
|
||||
response.setHeader("Location", newLocation, false);
|
||||
return;
|
||||
}
|
||||
if (queryString === "redir-test1") {
|
||||
response.write("test1-no-cors-ok");
|
||||
return;
|
||||
}
|
||||
|
||||
// TEST 2
|
||||
if (queryString === "test2") {
|
||||
var newLocation =
|
||||
"http://test1.example.com:443/tests/dom/security/test/csp/file_upgrade_insecure_cors_server.sjs?redir-test2";
|
||||
response.setStatusLine("1.1", 302, "Found");
|
||||
response.setHeader("Location", newLocation, false);
|
||||
return;
|
||||
}
|
||||
if (queryString === "redir-test2") {
|
||||
response.write("test2-no-cors-diffport-ok");
|
||||
return;
|
||||
}
|
||||
|
||||
// TEST 3
|
||||
response.setHeader("Access-Control-Allow-Headers", "content-type", false);
|
||||
response.setHeader("Access-Control-Allow-Methods", "POST, GET", false);
|
||||
response.setHeader("Access-Control-Allow-Origin", "*", false);
|
||||
|
||||
if (queryString === "test3") {
|
||||
var newLocation =
|
||||
"http://test1.example.com/tests/dom/security/test/csp/file_upgrade_insecure_cors_server.sjs?redir-test3";
|
||||
response.setStatusLine("1.1", 302, "Found");
|
||||
response.setHeader("Location", newLocation, false);
|
||||
return;
|
||||
}
|
||||
if (queryString === "redir-test3") {
|
||||
response.write("test3-cors-ok");
|
||||
return;
|
||||
}
|
||||
|
||||
// we should not get here, but just in case return something unexpected
|
||||
response.write("d'oh");
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Bug 1139297 - Implement CSP upgrade-insecure-requests directive</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- upgrade img from http:// to https:// -->
|
||||
<img id="testimage" src="http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_referrer_server.sjs?img"></img>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,56 @@
|
||||
// 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!");
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Bug 1139297 - Implement CSP upgrade-insecure-requests directive</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- upgrade img from http:// to https:// -->
|
||||
<img id="testimage" src="http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_reporting_server.sjs?img"></img>
|
||||
|
||||
<script type="application/javascript">
|
||||
var myImg = document.getElementById("testimage");
|
||||
myImg.onload = function(e) {
|
||||
window.parent.postMessage({result: "img-ok"}, "*");
|
||||
};
|
||||
myImg.onerror = function(e) {
|
||||
window.parent.postMessage({result: "img-error"}, "*");
|
||||
};
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,80 @@
|
||||
// Custom *.sjs specifically for the needs of Bug
|
||||
// Bug 1139297 - Implement CSP upgrade-insecure-requests directive
|
||||
|
||||
Components.utils.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
// small red image
|
||||
const IMG_BYTES = atob(
|
||||
"iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12" +
|
||||
"P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==");
|
||||
|
||||
const REPORT_URI = "https://example.com/tests/dom/security/test/csp/file_upgrade_insecure_reporting_server.sjs?report";
|
||||
const POLICY = "upgrade-insecure-requests; default-src https: 'unsafe-inline'";
|
||||
const POLICY_RO = "default-src https: 'unsafe-inline'; report-uri " + REPORT_URI;
|
||||
|
||||
function loadHTMLFromFile(path) {
|
||||
// Load the HTML to return in the response from file.
|
||||
// Since it's relative to the cwd of the test runner, we start there and
|
||||
// append to get to the actual path of the file.
|
||||
var testHTMLFile =
|
||||
Components.classes["@mozilla.org/file/directory_service;1"].
|
||||
getService(Components.interfaces.nsIProperties).
|
||||
get("CurWorkD", Components.interfaces.nsILocalFile);
|
||||
var dirs = path.split("/");
|
||||
for (var i = 0; i < dirs.length; i++) {
|
||||
testHTMLFile.append(dirs[i]);
|
||||
}
|
||||
var testHTMLFileStream =
|
||||
Components.classes["@mozilla.org/network/file-input-stream;1"].
|
||||
createInstance(Components.interfaces.nsIFileInputStream);
|
||||
testHTMLFileStream.init(testHTMLFile, -1, 0, 0);
|
||||
var testHTML = NetUtil.readInputStreamToString(testHTMLFileStream, testHTMLFileStream.available());
|
||||
return testHTML;
|
||||
}
|
||||
|
||||
|
||||
function handleRequest(request, response)
|
||||
{
|
||||
// avoid confusing cache behaviors
|
||||
response.setHeader("Cache-Control", "no-cache", false);
|
||||
|
||||
// (1) Store the query that will report back whether the violation report was received
|
||||
if (request.queryString == "queryresult") {
|
||||
response.processAsync();
|
||||
setObjectState("queryResult", response);
|
||||
return;
|
||||
}
|
||||
|
||||
// (2) We load a page using a CSP and a report only CSP
|
||||
if (request.queryString == "toplevel") {
|
||||
response.setHeader("Content-Security-Policy", POLICY, false);
|
||||
response.setHeader("Content-Security-Policy-Report-Only", POLICY_RO, false);
|
||||
response.setHeader("Content-Type", "text/html", false);
|
||||
response.write(loadHTMLFromFile("tests/dom/security/test/csp/file_upgrade_insecure_reporting.html"));
|
||||
return;
|
||||
}
|
||||
|
||||
// (3) Return the image back to the client
|
||||
if (request.queryString == "img") {
|
||||
response.setHeader("Content-Type", "image/png");
|
||||
response.write(IMG_BYTES);
|
||||
return;
|
||||
}
|
||||
|
||||
// (4) Finally we receive the report, let's return the request from (1)
|
||||
// signaling that we received the report correctly
|
||||
if (request.queryString == "report") {
|
||||
getObjectState("queryResult", function(queryResponse) {
|
||||
if (!queryResponse) {
|
||||
return;
|
||||
}
|
||||
queryResponse.write("report-ok");
|
||||
queryResponse.finish();
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// we should never get here, but just in case ...
|
||||
response.setHeader("Content-Type", "text/plain");
|
||||
response.write("doh!");
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
// Custom *.sjs file specifically for the needs of Bug:
|
||||
// Bug 1139297 - Implement CSP upgrade-insecure-requests directive
|
||||
|
||||
const TOTAL_EXPECTED_REQUESTS = 11;
|
||||
|
||||
const IFRAME_CONTENT =
|
||||
"<!DOCTYPE HTML>" +
|
||||
"<html>" +
|
||||
"<head><meta charset='utf-8'>" +
|
||||
"<title>Bug 1139297 - Implement CSP upgrade-insecure-requests directive</title>" +
|
||||
"</head>" +
|
||||
"<body>" +
|
||||
"<img src='http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_server.sjs?nested-img'></img>" +
|
||||
"</body>" +
|
||||
"</html>";
|
||||
|
||||
const expectedQueries = [ "script", "style", "img", "iframe", "form", "xhr",
|
||||
"media", "object", "font", "img-redir", "nested-img"];
|
||||
|
||||
function handleRequest(request, response)
|
||||
{
|
||||
// avoid confusing cache behaviors
|
||||
response.setHeader("Cache-Control", "no-cache", false);
|
||||
var queryString = request.queryString;
|
||||
|
||||
// initialize server variables and save the object state
|
||||
// of the initial request, which returns async once the
|
||||
// server has processed all requests.
|
||||
if (queryString == "queryresult") {
|
||||
setState("totaltests", TOTAL_EXPECTED_REQUESTS.toString());
|
||||
setState("receivedQueries", "");
|
||||
response.processAsync();
|
||||
setObjectState("queryResult", response);
|
||||
return;
|
||||
}
|
||||
|
||||
// handle img redirect (https->http)
|
||||
if (queryString == "redirect-image") {
|
||||
var newLocation =
|
||||
"http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_server.sjs?img-redir";
|
||||
response.setStatusLine("1.1", 302, "Found");
|
||||
response.setHeader("Location", newLocation, false);
|
||||
return;
|
||||
}
|
||||
|
||||
// just in case error handling for unexpected queries
|
||||
if (expectedQueries.indexOf(queryString) == -1) {
|
||||
response.write("doh!");
|
||||
return;
|
||||
}
|
||||
|
||||
// make sure all the requested queries are indeed https
|
||||
queryString += (request.scheme == "https") ? "-ok" : "-error";
|
||||
|
||||
var receivedQueries = getState("receivedQueries");
|
||||
|
||||
// images, scripts, etc. get queried twice, do not
|
||||
// confuse the server by storing the preload as
|
||||
// well as the actual load. If either the preload
|
||||
// or the actual load is not https, then we would
|
||||
// append "-error" in the array and the test would
|
||||
// fail at the end.
|
||||
if (receivedQueries.includes(queryString)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// append the result to the total query string array
|
||||
if (receivedQueries != "") {
|
||||
receivedQueries += ",";
|
||||
}
|
||||
receivedQueries += queryString;
|
||||
setState("receivedQueries", receivedQueries);
|
||||
|
||||
// keep track of how many more requests the server
|
||||
// is expecting
|
||||
var totaltests = parseInt(getState("totaltests"));
|
||||
totaltests -= 1;
|
||||
setState("totaltests", totaltests.toString());
|
||||
|
||||
// return content (img) for the nested iframe to test
|
||||
// that subresource requests within nested contexts
|
||||
// get upgraded as well. We also have to return
|
||||
// the iframe context in case of an error so we
|
||||
// can test both, using upgrade-insecure as well
|
||||
// as the base case of not using upgrade-insecure.
|
||||
if ((queryString == "iframe-ok") || (queryString == "iframe-error")) {
|
||||
response.write(IFRAME_CONTENT);
|
||||
}
|
||||
|
||||
// if we have received all the requests, we return
|
||||
// the result back.
|
||||
if (totaltests == 0) {
|
||||
getObjectState("queryResult", function(queryResponse) {
|
||||
if (!queryResponse) {
|
||||
return;
|
||||
}
|
||||
var receivedQueries = getState("receivedQueries");
|
||||
queryResponse.write(receivedQueries);
|
||||
queryResponse.finish();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
from mod_pywebsocket import msgutil
|
||||
|
||||
def web_socket_do_extra_handshake(request):
|
||||
pass
|
||||
|
||||
def web_socket_transfer_data(request):
|
||||
pass
|
||||
@@ -119,6 +119,15 @@ support-files =
|
||||
file_worker_redirect.sjs
|
||||
file_referrerdirective.html
|
||||
referrerdirective.sjs
|
||||
file_upgrade_insecure.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.html
|
||||
file_upgrade_insecure_referrer_server.sjs
|
||||
file_upgrade_insecure_cors.html
|
||||
file_upgrade_insecure_cors_server.sjs
|
||||
|
||||
[test_base-uri.html]
|
||||
[test_blob_data_schemes.html]
|
||||
@@ -173,3 +182,12 @@ skip-if = buildapp == 'b2g' # intermittent orange (bug 1028490)
|
||||
[test_referrerdirective.html]
|
||||
skip-if = buildapp == 'b2g' #no ssl support
|
||||
[test_worker_redirect.html]
|
||||
[test_upgrade_insecure.html]
|
||||
# no ssl support as well as websocket tests do not work (see test_websocket.html)
|
||||
skip-if = buildapp == 'b2g' || buildapp == 'mulet' || toolkit == 'gonk' || toolkit == 'android'
|
||||
[test_upgrade_insecure_reporting.html]
|
||||
skip-if = buildapp == 'b2g' || buildapp == 'mulet' || toolkit == 'gonk' || toolkit == 'android'
|
||||
[test_upgrade_insecure_referrer.html]
|
||||
skip-if = buildapp == 'b2g' || buildapp == 'mulet' || toolkit == 'gonk' || toolkit == 'android'
|
||||
[test_upgrade_insecure_cors.html]
|
||||
skip-if = buildapp == 'b2g' || buildapp == 'mulet' || toolkit == 'gonk' || toolkit == 'android'
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
<!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 resources (img, script, sytle, etc) over *http* and make sure
|
||||
* that all the resources get upgraded to use >> https << when the
|
||||
* csp-directive "upgrade-insecure-requests" is specified. We further
|
||||
* test that subresources within nested contexts (iframes) get upgraded
|
||||
* and also test the handling of server side redirects.
|
||||
*
|
||||
* In detail:
|
||||
* We perform an XHR request to the *.sjs file which is processed async on
|
||||
* the server and waits till all the requests were processed by the server.
|
||||
* Once the server received all the different requests, the server responds
|
||||
* to the initial XHR request with an array of results which must match
|
||||
* the expected results from each test, making sure that all requests
|
||||
* received by the server (*.sjs) were actually *https* requests.
|
||||
*/
|
||||
|
||||
const UPGRADE_POLICY =
|
||||
"upgrade-insecure-requests;" + // upgrade all http requests to https
|
||||
"default-src https: wss: 'unsafe-inline';" + // only allow https: and wss:
|
||||
"form-action https:;"; // explicit, no fallback to default-src
|
||||
|
||||
const UPGRADE_POLICY_NO_DEFAULT_SRC =
|
||||
"upgrade-insecure-requests;" + // upgrade all http requests to https
|
||||
"script-src 'unsafe-inline' *"; // we have to whitelist the inline scripts
|
||||
// in the test.
|
||||
|
||||
const NO_UPGRADE_POLICY =
|
||||
"default-src http: ws: 'unsafe-inline';" + // allow http:// and ws://
|
||||
"form-action http:;"; // explicit, no fallback to default-src
|
||||
|
||||
var tests = [
|
||||
{ // (1) test that all requests within an >> https << page get updated
|
||||
policy: UPGRADE_POLICY,
|
||||
topLevelScheme: "https://",
|
||||
description: "upgrade all requests on toplevel https",
|
||||
results: [
|
||||
"iframe-ok", "script-ok", "img-ok", "img-redir-ok", "font-ok", "xhr-ok", "style-ok",
|
||||
"media-ok", "object-ok", "form-ok", "websocket-ok", "nested-img-ok"
|
||||
]
|
||||
},
|
||||
{ // (2) test that all requests within an >> http << page get updated
|
||||
policy: UPGRADE_POLICY,
|
||||
topLevelScheme: "http://",
|
||||
description: "upgrade all requests on toplevel http",
|
||||
results: [
|
||||
"iframe-ok", "script-ok", "img-ok", "img-redir-ok", "font-ok", "xhr-ok", "style-ok",
|
||||
"media-ok", "object-ok", "form-ok", "websocket-ok", "nested-img-ok"
|
||||
]
|
||||
},
|
||||
{ // (3) test that all requests within an >> http << page get updated, but do
|
||||
// not specify a default-src directive.
|
||||
policy: UPGRADE_POLICY_NO_DEFAULT_SRC,
|
||||
topLevelScheme: "http://",
|
||||
description: "upgrade all requests on toplevel http where default-src is not specified",
|
||||
results: [
|
||||
"iframe-ok", "script-ok", "img-ok", "img-redir-ok", "font-ok", "xhr-ok", "style-ok",
|
||||
"media-ok", "object-ok", "form-ok", "websocket-ok", "nested-img-ok"
|
||||
]
|
||||
},
|
||||
{ // (4) test that no requests get updated if >> upgrade-insecure-requests << is not used
|
||||
policy: NO_UPGRADE_POLICY,
|
||||
topLevelScheme: "http://",
|
||||
description: "do not upgrade any requests on toplevel http",
|
||||
results: [
|
||||
"iframe-error", "script-error", "img-error", "img-redir-error", "font-error",
|
||||
"xhr-error", "style-error", "media-error", "object-error", "form-error",
|
||||
"websocket-error", "nested-img-error"
|
||||
]
|
||||
},
|
||||
];
|
||||
|
||||
var counter = 0;
|
||||
var curTest;
|
||||
|
||||
function loadTestPage() {
|
||||
curTest = tests[counter++];
|
||||
var src = curTest.topLevelScheme + "example.com/tests/dom/security/test/csp/file_testserver.sjs?file=";
|
||||
// append the file that should be served
|
||||
src += escape("tests/dom/security/test/csp/file_upgrade_insecure.html")
|
||||
// append the CSP that should be used to serve the file
|
||||
src += "&csp=" + escape(curTest.policy);
|
||||
document.getElementById("testframe").src = src;
|
||||
}
|
||||
|
||||
function finishTest() {
|
||||
window.removeEventListener("message", receiveMessage, false);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
function checkResults(result) {
|
||||
// try to find the expected result within the results array
|
||||
var index = curTest.results.indexOf(result);
|
||||
isnot(index, -1, curTest.description + " (result: " + result + ")");
|
||||
|
||||
// take the element out the array and continue till the results array is empty
|
||||
if (index != -1) {
|
||||
curTest.results.splice(index, 1);
|
||||
}
|
||||
// lets check if we are expecting more results to bubble up
|
||||
if (curTest.results.length > 0) {
|
||||
return;
|
||||
}
|
||||
// lets see if we ran all the tests
|
||||
if (counter == tests.length) {
|
||||
finishTest();
|
||||
return;
|
||||
}
|
||||
// otherwise it's time to run the next test
|
||||
runNextTest();
|
||||
}
|
||||
|
||||
// a postMessage handler that is used by sandboxed iframes without
|
||||
// 'allow-same-origin' to bubble up results back to this main page.
|
||||
window.addEventListener("message", receiveMessage, false);
|
||||
function receiveMessage(event) {
|
||||
checkResults(event.data.result);
|
||||
}
|
||||
|
||||
function runNextTest() {
|
||||
// sends an xhr request to the server which is processed async, which only
|
||||
// returns after the server has received all the expected requests.
|
||||
var myXHR = new XMLHttpRequest();
|
||||
myXHR.open("GET", "file_upgrade_insecure_server.sjs?queryresult");
|
||||
myXHR.onload = function(e) {
|
||||
var results = myXHR.responseText.split(",");
|
||||
for (var index in results) {
|
||||
checkResults(results[index]);
|
||||
}
|
||||
}
|
||||
myXHR.onerror = function(e) {
|
||||
ok(false, "could not query results from server (" + e.message + ")");
|
||||
finishTest();
|
||||
}
|
||||
myXHR.send();
|
||||
|
||||
// give it some time and run the testpage
|
||||
SimpleTest.executeSoon(loadTestPage);
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
runNextTest();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,86 @@
|
||||
<!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 serving two XHR requests (including being redirected);
|
||||
* one that should not require CORS and one that should require cors, in particular:
|
||||
*
|
||||
* Test 1:
|
||||
* Main page: https://test1.example.com
|
||||
* XHR request: http://test1.example.com
|
||||
* Redirect to: http://test1.example.com
|
||||
* Description: Upgrade insecure should upgrade from http to https and also
|
||||
* surpress CORS for that case.
|
||||
*
|
||||
* Test 2:
|
||||
* Main page: https://test1.example.com
|
||||
* XHR request: http://test1.example.com
|
||||
* Redirect to: http://test1.example.com:443
|
||||
* Description: Upgrade insecure should upgrade from http to https and also
|
||||
* prevent CORS for that case.
|
||||
* Note: If redirecting to a different port, then CORS *should* be enforced (unless
|
||||
* it's port 443). Unfortunately we can't test that because of the setup of our
|
||||
* *.sjs files; they only are able to listen to port 443, see:
|
||||
* http://mxr.mozilla.org/mozilla-central/source/build/pgo/server-locations.txt#98
|
||||
*
|
||||
* Test 3:
|
||||
* Main page: https://test1.example.com
|
||||
* XHR request: http://test2.example.com
|
||||
* Redirect to: http://test1.example.com
|
||||
* Description: Upgrade insecure should *not* prevent CORS since
|
||||
* the page performs a cross origin xhr.
|
||||
*
|
||||
*/
|
||||
|
||||
const CSP_POLICY = "upgrade-insecure-requests; script-src 'unsafe-inline'";
|
||||
var tests = 3;
|
||||
|
||||
function loadTest() {
|
||||
var src = "https://test1.example.com/tests/dom/security/test/csp/file_testserver.sjs?file=";
|
||||
// append the file that should be served
|
||||
src += escape("tests/dom/security/test/csp/file_upgrade_insecure_cors.html")
|
||||
// append the CSP that should be used to serve the file
|
||||
src += "&csp=" + escape(CSP_POLICY);
|
||||
document.getElementById("testframe").src = src;
|
||||
}
|
||||
|
||||
function checkResult(result) {
|
||||
if (result === "test1-no-cors-ok" ||
|
||||
result === "test2-no-cors-diffport-ok" ||
|
||||
result === "test3-cors-ok") {
|
||||
ok(true, "'upgrade-insecure-requests' acknowledges CORS (" + result + ")");
|
||||
}
|
||||
else {
|
||||
ok(false, "'upgrade-insecure-requests' acknowledges CORS (" + result + ")");
|
||||
}
|
||||
if (--tests > 0) {
|
||||
return;
|
||||
}
|
||||
window.removeEventListener("message", receiveMessage, false);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
// a postMessage handler that is used to bubble up results from
|
||||
// within the iframe.
|
||||
window.addEventListener("message", receiveMessage, false);
|
||||
function receiveMessage(event) {
|
||||
checkResult(event.data);
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
loadTest();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,79 @@
|
||||
<!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.
|
||||
*/
|
||||
|
||||
const PRE_POLICY = "upgrade-insecure-requests; default-src https:; ";
|
||||
|
||||
var tests = [
|
||||
{
|
||||
policy: "referrer origin",
|
||||
description: "upgrade insecure request with referrer = origin",
|
||||
result: "http://example.com"
|
||||
},
|
||||
{
|
||||
policy: "referrer no-referrer",
|
||||
description: "upgrade insecure request with referrer = no-referrer",
|
||||
result: ""
|
||||
}
|
||||
];
|
||||
|
||||
var counter = 0;
|
||||
var curTest;
|
||||
|
||||
function loadTestPage() {
|
||||
curTest = tests[counter++];
|
||||
var src = "http://example.com/tests/dom/security/test/csp/file_testserver.sjs?file=";
|
||||
// append the file that should be served
|
||||
src += escape("tests/dom/security/test/csp/file_upgrade_insecure_referrer.html")
|
||||
// append the CSP that should be used to serve the file
|
||||
src += "&csp=" + escape(PRE_POLICY + curTest.policy);
|
||||
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>
|
||||
@@ -0,0 +1,69 @@
|
||||
<!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 an https page which includes an http image. We make sure that
|
||||
* the image request gets upgraded to https but also make sure that a report
|
||||
* is sent when a CSP report only is used which only allows https requests.
|
||||
*/
|
||||
|
||||
var expectedResults = 2;
|
||||
|
||||
function finishTest() {
|
||||
// let's wait till the image was loaded and the report was received
|
||||
if (--expectedResults > 0) {
|
||||
return;
|
||||
}
|
||||
window.removeEventListener("message", receiveMessage, false);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
// (1) Lets send off an XHR request which will return once the server receives
|
||||
// the violation report from the report only policy.
|
||||
var myXHR = new XMLHttpRequest();
|
||||
myXHR.open("GET", "file_upgrade_insecure_reporting_server.sjs?queryresult");
|
||||
myXHR.onload = function(e) {
|
||||
is(myXHR.responseText, "report-ok", "csp-report was sent correctly");
|
||||
finishTest();
|
||||
}
|
||||
myXHR.onerror = function(e) {
|
||||
ok(false, "could not query result for csp-report from server (" + e.message + ")");
|
||||
finishTest();
|
||||
}
|
||||
myXHR.send();
|
||||
|
||||
// (2) We load a page that is served using a CSP and a CSP report only which loads
|
||||
// an image over http.
|
||||
SimpleTest.executeSoon(function() {
|
||||
document.getElementById("testframe").src =
|
||||
"https://example.com/tests/dom/security/test/csp/file_upgrade_insecure_reporting_server.sjs?toplevel";
|
||||
});
|
||||
}
|
||||
|
||||
// a postMessage handler that is used by sandboxed iframes without
|
||||
// 'allow-same-origin' to bubble up results back to this main page.
|
||||
window.addEventListener("message", receiveMessage, false);
|
||||
function receiveMessage(event) {
|
||||
// (3) make sure the image was correctly loaded
|
||||
is(event.data.result, "img-ok", "upgraded insecure image load from http -> https");
|
||||
finishTest();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
runTest();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -25,6 +25,7 @@ dictionary CSP {
|
||||
sequence<DOMString> form-action;
|
||||
sequence<DOMString> referrer;
|
||||
sequence<DOMString> manifest-src;
|
||||
sequence<DOMString> upgrade-insecure-requests;
|
||||
};
|
||||
|
||||
dictionary CSPPolicies {
|
||||
|
||||
@@ -184,6 +184,7 @@ private:
|
||||
DECL_GFX_PREF(Live, "apz.y_stationary_size_multiplier", APZYStationarySizeMultiplier, float, 3.5f);
|
||||
DECL_GFX_PREF(Live, "apz.zoom_animation_duration_ms", APZZoomAnimationDuration, int32_t, 250);
|
||||
|
||||
DECL_GFX_PREF(Live, "dom.meta-viewport.enabled", MetaViewportEnabled, bool, false);
|
||||
DECL_GFX_PREF(Once, "dom.vr.enabled", VREnabled, bool, false);
|
||||
DECL_GFX_PREF(Once, "dom.vr.add-test-devices", VRAddTestDevices, int32_t, 1);
|
||||
DECL_GFX_PREF(Live, "dom.w3c_pointer_events.enabled", PointerEventsEnabled, bool, false);
|
||||
|
||||
@@ -233,6 +233,7 @@ LoadInfoToLoadInfoArgs(nsILoadInfo *aLoadInfo,
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
aLoadInfoArgs->securityFlags() = aLoadInfo->GetSecurityFlags();
|
||||
aLoadInfoArgs->contentPolicyType() = aLoadInfo->InternalContentPolicyType();
|
||||
aLoadInfoArgs->upgradeInsecureRequests() = aLoadInfo->GetUpgradeInsecureRequests();
|
||||
aLoadInfoArgs->innerWindowID() = aLoadInfo->GetInnerWindowID();
|
||||
aLoadInfoArgs->outerWindowID() = aLoadInfo->GetOuterWindowID();
|
||||
aLoadInfoArgs->parentOuterWindowID() = aLoadInfo->GetParentOuterWindowID();
|
||||
@@ -248,6 +249,7 @@ LoadInfoToLoadInfoArgs(nsILoadInfo *aLoadInfo,
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
aLoadInfoArgs->securityFlags() = nsILoadInfo::SEC_NORMAL;
|
||||
aLoadInfoArgs->contentPolicyType() = nsIContentPolicy::TYPE_OTHER;
|
||||
aLoadInfoArgs->upgradeInsecureRequests() = false;
|
||||
aLoadInfoArgs->innerWindowID() = 0;
|
||||
aLoadInfoArgs->outerWindowID() = 0;
|
||||
aLoadInfoArgs->parentOuterWindowID() = 0;
|
||||
@@ -271,6 +273,7 @@ LoadInfoArgsToLoadInfo(const mozilla::net::LoadInfoArgs& aLoadInfoArgs,
|
||||
triggeringPrincipal,
|
||||
aLoadInfoArgs.securityFlags(),
|
||||
aLoadInfoArgs.contentPolicyType(),
|
||||
aLoadInfoArgs.upgradeInsecureRequests(),
|
||||
aLoadInfoArgs.innerWindowID(),
|
||||
aLoadInfoArgs.outerWindowID(),
|
||||
aLoadInfoArgs.parentOuterWindowID());
|
||||
|
||||
@@ -136,9 +136,9 @@ public:
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
for (size_t i = 0; i < mRefreshDrivers.Length(); i++) {
|
||||
aNewTimer->AddRefreshDriver(mRefreshDrivers[i]);
|
||||
mRefreshDrivers[i]->mActiveTimer = aNewTimer;
|
||||
for (nsRefreshDriver* driver : mRefreshDrivers) {
|
||||
aNewTimer->AddRefreshDriver(driver);
|
||||
driver->mActiveTimer = aNewTimer;
|
||||
}
|
||||
mRefreshDrivers.Clear();
|
||||
|
||||
@@ -176,13 +176,13 @@ protected:
|
||||
nsTArray<nsRefPtr<nsRefreshDriver> > drivers(mRefreshDrivers);
|
||||
// RD is short for RefreshDriver
|
||||
profiler_tracing("Paint", "RD", TRACING_INTERVAL_START);
|
||||
for (size_t i = 0; i < drivers.Length(); ++i) {
|
||||
for (nsRefreshDriver* driver : drivers) {
|
||||
// don't poke this driver if it's in test mode
|
||||
if (drivers[i]->IsTestControllingRefreshesEnabled()) {
|
||||
if (driver->IsTestControllingRefreshesEnabled()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
TickDriver(drivers[i], jsnow, now);
|
||||
TickDriver(driver, jsnow, now);
|
||||
}
|
||||
profiler_tracing("Paint", "RD", TRACING_INTERVAL_END);
|
||||
LOG("[%p] done.", this);
|
||||
@@ -1044,8 +1044,8 @@ nsRefreshDriver::~nsRefreshDriver()
|
||||
mRootRefresh->RemoveRefreshObserver(this, Flush_Style);
|
||||
mRootRefresh = nullptr;
|
||||
}
|
||||
for (uint32_t i = 0; i < mPresShellsToInvalidateIfHidden.Length(); i++) {
|
||||
mPresShellsToInvalidateIfHidden[i]->InvalidatePresShellIfHidden();
|
||||
for (nsIPresShell* shell : mPresShellsToInvalidateIfHidden) {
|
||||
shell->InvalidatePresShellIfHidden();
|
||||
}
|
||||
mPresShellsToInvalidateIfHidden.Clear();
|
||||
|
||||
@@ -1526,34 +1526,34 @@ nsRefreshDriver::RunFrameRequestCallbacks(int64_t aNowEpoch, TimeStamp aNowTime)
|
||||
// Reset mFrameRequestCallbackDocs so they can be readded as needed.
|
||||
mFrameRequestCallbackDocs.Clear();
|
||||
|
||||
profiler_tracing("Paint", "Scripts", TRACING_INTERVAL_START);
|
||||
int64_t eventTime = aNowEpoch / PR_USEC_PER_MSEC;
|
||||
for (uint32_t i = 0; i < frameRequestCallbacks.Length(); ++i) {
|
||||
const DocumentFrameCallbacks& docCallbacks = frameRequestCallbacks[i];
|
||||
// XXXbz Bug 863140: GetInnerWindow can return the outer
|
||||
// window in some cases.
|
||||
nsPIDOMWindow* innerWindow = docCallbacks.mDocument->GetInnerWindow();
|
||||
DOMHighResTimeStamp timeStamp = 0;
|
||||
if (innerWindow && innerWindow->IsInnerWindow()) {
|
||||
nsPerformance* perf = innerWindow->GetPerformance();
|
||||
if (perf) {
|
||||
timeStamp = perf->GetDOMTiming()->TimeStampToDOMHighRes(aNowTime);
|
||||
if (!frameRequestCallbacks.IsEmpty()) {
|
||||
profiler_tracing("Paint", "Scripts", TRACING_INTERVAL_START);
|
||||
int64_t eventTime = aNowEpoch / PR_USEC_PER_MSEC;
|
||||
for (const DocumentFrameCallbacks& docCallbacks : frameRequestCallbacks) {
|
||||
// XXXbz Bug 863140: GetInnerWindow can return the outer
|
||||
// window in some cases.
|
||||
nsPIDOMWindow* innerWindow = docCallbacks.mDocument->GetInnerWindow();
|
||||
DOMHighResTimeStamp timeStamp = 0;
|
||||
if (innerWindow && innerWindow->IsInnerWindow()) {
|
||||
nsPerformance* perf = innerWindow->GetPerformance();
|
||||
if (perf) {
|
||||
timeStamp = perf->GetDOMTiming()->TimeStampToDOMHighRes(aNowTime);
|
||||
}
|
||||
// else window is partially torn down already
|
||||
}
|
||||
// else window is partially torn down already
|
||||
}
|
||||
for (uint32_t j = 0; j < docCallbacks.mCallbacks.Length(); ++j) {
|
||||
const nsIDocument::FrameRequestCallbackHolder& holder =
|
||||
docCallbacks.mCallbacks[j];
|
||||
nsAutoMicroTask mt;
|
||||
if (holder.HasWebIDLCallback()) {
|
||||
ErrorResult ignored;
|
||||
holder.GetWebIDLCallback()->Call(timeStamp, ignored);
|
||||
} else {
|
||||
holder.GetXPCOMCallback()->Sample(eventTime);
|
||||
for (const nsIDocument::FrameRequestCallbackHolder& holder :
|
||||
docCallbacks.mCallbacks) {
|
||||
nsAutoMicroTask mt;
|
||||
if (holder.HasWebIDLCallback()) {
|
||||
ErrorResult ignored;
|
||||
holder.GetWebIDLCallback()->Call(timeStamp, ignored);
|
||||
} else {
|
||||
holder.GetXPCOMCallback()->Sample(eventTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
profiler_tracing("Paint", "Scripts", TRACING_INTERVAL_END);
|
||||
}
|
||||
profiler_tracing("Paint", "Scripts", TRACING_INTERVAL_END);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1755,19 +1755,18 @@ nsRefreshDriver::Tick(int64_t aNowEpoch, TimeStamp aNowTime)
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < mPresShellsToInvalidateIfHidden.Length(); i++) {
|
||||
mPresShellsToInvalidateIfHidden[i]->InvalidatePresShellIfHidden();
|
||||
for (nsIPresShell* shell : mPresShellsToInvalidateIfHidden) {
|
||||
shell->InvalidatePresShellIfHidden();
|
||||
}
|
||||
mPresShellsToInvalidateIfHidden.Clear();
|
||||
|
||||
if (mViewManagerFlushIsPending) {
|
||||
nsTArray<nsDocShell*> profilingDocShells;
|
||||
GetProfileTimelineSubDocShells(GetDocShell(mPresContext), profilingDocShells);
|
||||
for (uint32_t i = 0; i < profilingDocShells.Length(); i ++) {
|
||||
for (nsDocShell* docShell : profilingDocShells) {
|
||||
// For the sake of the profile timeline's simplicity, this is flagged as
|
||||
// paint even if it includes creating display lists
|
||||
profilingDocShells[i]->AddProfileTimelineMarker("Paint",
|
||||
TRACING_INTERVAL_START);
|
||||
docShell->AddProfileTimelineMarker("Paint", TRACING_INTERVAL_START);
|
||||
}
|
||||
profiler_tracing("Paint", "DisplayList", TRACING_INTERVAL_START);
|
||||
#ifdef MOZ_DUMP_PAINTING
|
||||
@@ -1784,9 +1783,8 @@ nsRefreshDriver::Tick(int64_t aNowEpoch, TimeStamp aNowTime)
|
||||
printf_stderr("Ending ProcessPendingUpdates\n");
|
||||
}
|
||||
#endif
|
||||
for (uint32_t i = 0; i < profilingDocShells.Length(); i ++) {
|
||||
profilingDocShells[i]->AddProfileTimelineMarker("Paint",
|
||||
TRACING_INTERVAL_END);
|
||||
for (nsDocShell* docShell : profilingDocShells) {
|
||||
docShell->AddProfileTimelineMarker("Paint", TRACING_INTERVAL_END);
|
||||
}
|
||||
profiler_tracing("Paint", "DisplayList", TRACING_INTERVAL_END);
|
||||
|
||||
@@ -1800,8 +1798,10 @@ nsRefreshDriver::Tick(int64_t aNowEpoch, TimeStamp aNowTime)
|
||||
mozilla::Telemetry::AccumulateTimeDelta(mozilla::Telemetry::REFRESH_DRIVER_TICK, mTickStart);
|
||||
#endif
|
||||
|
||||
for (uint32_t i = 0; i < mPostRefreshObservers.Length(); ++i) {
|
||||
mPostRefreshObservers[i]->DidRefresh();
|
||||
nsTObserverArray<nsAPostRefreshObserver*>::ForwardIterator iter(mPostRefreshObservers);
|
||||
while (iter.HasMore()) {
|
||||
nsAPostRefreshObserver* observer = iter.GetNext();
|
||||
observer->DidRefresh();
|
||||
}
|
||||
|
||||
// Check if we should exit high precision timer mode.
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "nsTObserverArray.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsTHashtable.h"
|
||||
#include "nsTObserverArray.h"
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
@@ -398,7 +399,7 @@ private:
|
||||
// nsTArray on purpose, because we want to be able to swap.
|
||||
nsTArray<nsIDocument*> mFrameRequestCallbackDocs;
|
||||
nsTArray<nsIDocument*> mThrottledFrameRequestCallbackDocs;
|
||||
nsTArray<nsAPostRefreshObserver*> mPostRefreshObservers;
|
||||
nsTObserverArray<nsAPostRefreshObserver*> mPostRefreshObservers;
|
||||
|
||||
// Helper struct for processing image requests
|
||||
struct ImageRequestParameters {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "nsIFrameLoader.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsISupportsUtils.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@@ -31,6 +32,7 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal,
|
||||
, mSecurityFlags(aSecurityFlags)
|
||||
, mInternalContentPolicyType(aContentPolicyType)
|
||||
, mBaseURI(aBaseURI)
|
||||
, mUpgradeInsecureRequests(false)
|
||||
, mInnerWindowID(0)
|
||||
, mOuterWindowID(0)
|
||||
, mParentOuterWindowID(0)
|
||||
@@ -74,6 +76,8 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal,
|
||||
nsCOMPtr<nsPIDOMWindow> parent = outerWindow->GetScriptableParent();
|
||||
mParentOuterWindowID = parent->WindowID();
|
||||
}
|
||||
|
||||
mUpgradeInsecureRequests = aLoadingContext->OwnerDoc()->GetUpgradeInsecureRequests();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,6 +85,7 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal,
|
||||
nsIPrincipal* aTriggeringPrincipal,
|
||||
nsSecurityFlags aSecurityFlags,
|
||||
nsContentPolicyType aContentPolicyType,
|
||||
bool aUpgradeInsecureRequests,
|
||||
uint64_t aInnerWindowID,
|
||||
uint64_t aOuterWindowID,
|
||||
uint64_t aParentOuterWindowID)
|
||||
@@ -88,6 +93,7 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal,
|
||||
, mTriggeringPrincipal(aTriggeringPrincipal)
|
||||
, mSecurityFlags(aSecurityFlags)
|
||||
, mInternalContentPolicyType(aContentPolicyType)
|
||||
, mUpgradeInsecureRequests(aUpgradeInsecureRequests)
|
||||
, mInnerWindowID(aInnerWindowID)
|
||||
, mOuterWindowID(aOuterWindowID)
|
||||
, mParentOuterWindowID(aParentOuterWindowID)
|
||||
@@ -204,6 +210,13 @@ LoadInfo::BaseURI()
|
||||
return mBaseURI;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetUpgradeInsecureRequests(bool* aResult)
|
||||
{
|
||||
*aResult = mUpgradeInsecureRequests;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetInnerWindowID(uint64_t* aResult)
|
||||
{
|
||||
|
||||
@@ -61,6 +61,7 @@ private:
|
||||
nsIPrincipal* aTriggeringPrincipal,
|
||||
nsSecurityFlags aSecurityFlags,
|
||||
nsContentPolicyType aContentPolicyType,
|
||||
bool aUpgradeInsecureRequests,
|
||||
uint64_t aInnerWindowID,
|
||||
uint64_t aOuterWindowID,
|
||||
uint64_t aParentOuterWindowID);
|
||||
@@ -73,13 +74,14 @@ private:
|
||||
|
||||
nsCOMPtr<nsIPrincipal> mLoadingPrincipal;
|
||||
nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
|
||||
nsWeakPtr mLoadingContext;
|
||||
nsSecurityFlags mSecurityFlags;
|
||||
nsContentPolicyType mInternalContentPolicyType;
|
||||
nsCOMPtr<nsIURI> mBaseURI;
|
||||
uint64_t mInnerWindowID;
|
||||
uint64_t mOuterWindowID;
|
||||
uint64_t mParentOuterWindowID;
|
||||
nsWeakPtr mLoadingContext;
|
||||
nsSecurityFlags mSecurityFlags;
|
||||
nsContentPolicyType mInternalContentPolicyType;
|
||||
nsCOMPtr<nsIURI> mBaseURI;
|
||||
bool mUpgradeInsecureRequests;
|
||||
uint64_t mInnerWindowID;
|
||||
uint64_t mOuterWindowID;
|
||||
uint64_t mParentOuterWindowID;
|
||||
|
||||
// Is true if this load was triggered by processing the attributes of the
|
||||
// browsing context container.
|
||||
|
||||
@@ -17,7 +17,7 @@ typedef unsigned long nsSecurityFlags;
|
||||
/**
|
||||
* An nsILoadOwner represents per-load information about who started the load.
|
||||
*/
|
||||
[scriptable, builtinclass, uuid(dcf54f49-2d63-4c34-9da1-54df235f354c)]
|
||||
[scriptable, builtinclass, uuid(6b7f8798-3c28-44fc-8b1a-cd613eb826c5)]
|
||||
interface nsILoadInfo : nsISupports
|
||||
{
|
||||
/**
|
||||
@@ -184,7 +184,6 @@ interface nsILoadInfo : nsISupports
|
||||
[noscript, notxpcom]
|
||||
nsContentPolicyType internalContentPolicyType();
|
||||
|
||||
|
||||
/**
|
||||
* A base URI for use in situations where it cannot otherwise be inferred.
|
||||
* This attribute may be null. The value of this attribute may be
|
||||
@@ -198,6 +197,27 @@ interface nsILoadInfo : nsISupports
|
||||
[noscript, notxpcom, nostdcall, binaryname(BaseURI)]
|
||||
nsIURI binaryBaseURI();
|
||||
|
||||
/**
|
||||
* Returns true if document or any of the documents ancestors
|
||||
* up to the toplevel document make use of the CSP directive
|
||||
* 'upgrade-insecure-requests'. Used to identify upgrade
|
||||
* requests in e10s where the loadingDocument is not available.
|
||||
*
|
||||
* Warning: If the loadingDocument is null, then the
|
||||
* upgradeInsecureRequests is false.
|
||||
*/
|
||||
readonly attribute boolean upgradeInsecureRequests;
|
||||
|
||||
%{ C++
|
||||
inline bool GetUpgradeInsecureRequests()
|
||||
{
|
||||
bool result;
|
||||
mozilla::DebugOnly<nsresult> rv = GetUpgradeInsecureRequests(&result);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
return result;
|
||||
}
|
||||
%}
|
||||
|
||||
/**
|
||||
* Typically these are the window IDs of the window in which the element being
|
||||
* loaded lives. However, if the element being loaded is <frame
|
||||
|
||||
@@ -30,6 +30,7 @@ struct LoadInfoArgs
|
||||
PrincipalInfo triggeringPrincipalInfo;
|
||||
uint32_t securityFlags;
|
||||
uint32_t contentPolicyType;
|
||||
bool upgradeInsecureRequests;
|
||||
uint64_t innerWindowID;
|
||||
uint64_t outerWindowID;
|
||||
uint64_t parentOuterWindowID;
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
// HttpLog.h should generally be included first
|
||||
#include "HttpLog.h"
|
||||
|
||||
#include "mozilla/dom/nsCSPUtils.h"
|
||||
#include "mozilla/dom/nsCSPContext.h"
|
||||
#include "nsHttp.h"
|
||||
#include "nsHttpChannel.h"
|
||||
#include "nsHttpHandler.h"
|
||||
@@ -309,7 +311,48 @@ nsHttpChannel::Connect()
|
||||
rv = mURI->SchemeIs("https", &isHttps);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
if (mAllowSTS && !isHttps) {
|
||||
if (!isHttps) {
|
||||
// If any of the documents up the chain to the root doucment makes use of
|
||||
// the CSP directive 'upgrade-insecure-requests', then it's time to fulfill
|
||||
// the promise to CSP and mixed content blocking to upgrade the channel
|
||||
// from http to https.
|
||||
if (mLoadInfo && mLoadInfo->GetUpgradeInsecureRequests()) {
|
||||
// Please note that cross origin top level navigations are not subject
|
||||
// to upgrade-insecure-requests, see:
|
||||
// http://www.w3.org/TR/upgrade-insecure-requests/#examples
|
||||
nsCOMPtr<nsIPrincipal> resultPrincipal;
|
||||
nsContentUtils::GetSecurityManager()->
|
||||
GetChannelResultPrincipal(this, getter_AddRefs(resultPrincipal));
|
||||
bool crossOriginNavigation =
|
||||
(mLoadInfo->GetExternalContentPolicyType() == nsIContentPolicy::TYPE_DOCUMENT) &&
|
||||
(!resultPrincipal->Equals(mLoadInfo->LoadingPrincipal()));
|
||||
|
||||
if (!crossOriginNavigation) {
|
||||
// let's log a message to the console that we are upgrading a request
|
||||
nsAutoCString spec, scheme;
|
||||
mURI->GetSpec(spec);
|
||||
mURI->GetScheme(scheme);
|
||||
// append the additional 's' for security to the scheme :-)
|
||||
scheme.AppendASCII("s");
|
||||
NS_ConvertUTF8toUTF16 reportSpec(spec);
|
||||
NS_ConvertUTF8toUTF16 reportScheme(scheme);
|
||||
|
||||
const char16_t* params[] = { reportSpec.get(), reportScheme.get() };
|
||||
uint32_t innerWindowId = mLoadInfo ? mLoadInfo->GetInnerWindowID() : 0;
|
||||
CSP_LogLocalizedStr(NS_LITERAL_STRING("upgradeInsecureRequest").get(),
|
||||
params, ArrayLength(params),
|
||||
EmptyString(), // aSourceFile
|
||||
EmptyString(), // aScriptSample
|
||||
0, // aLineNumber
|
||||
0, // aColumnNumber
|
||||
nsIScriptError::warningFlag, "CSP",
|
||||
innerWindowId);
|
||||
|
||||
//Telemetry::Accumulate(Telemetry::HTTP_SCHEME_UPGRADE, 4);
|
||||
return AsyncCall(&nsHttpChannel::HandleAsyncRedirectChannelToHttps);
|
||||
}
|
||||
}
|
||||
|
||||
// enforce Strict-Transport-Security
|
||||
nsISiteSecurityService* sss = gHttpHandler->GetSSService();
|
||||
NS_ENSURE_TRUE(sss, NS_ERROR_OUT_OF_MEMORY);
|
||||
@@ -326,8 +369,17 @@ nsHttpChannel::Connect()
|
||||
|
||||
if (isStsHost) {
|
||||
LOG(("nsHttpChannel::Connect() STS permissions found\n"));
|
||||
return AsyncCall(&nsHttpChannel::HandleAsyncRedirectChannelToHttps);
|
||||
if (mAllowSTS) {
|
||||
//Telemetry::Accumulate(Telemetry::HTTP_SCHEME_UPGRADE, 3);
|
||||
return AsyncCall(&nsHttpChannel::HandleAsyncRedirectChannelToHttps);
|
||||
} else {
|
||||
//Telemetry::Accumulate(Telemetry::HTTP_SCHEME_UPGRADE, 2);
|
||||
}
|
||||
} else {
|
||||
//Telemetry::Accumulate(Telemetry::HTTP_SCHEME_UPGRADE, 1);
|
||||
}
|
||||
} else {
|
||||
//Telemetry::Accumulate(Telemetry::HTTP_SCHEME_UPGRADE, 0);
|
||||
}
|
||||
|
||||
// ensure that we are using a valid hostname
|
||||
@@ -2386,7 +2438,7 @@ nsHttpChannel::ProcessPartialContent()
|
||||
LOG(("nsHttpChannel::ProcessPartialContent [this=%p] "
|
||||
"206 has different total entity size than the content length "
|
||||
"of the original partially cached entity.\n", this));
|
||||
|
||||
|
||||
mCacheEntry->AsyncDoom(nullptr);
|
||||
Cancel(NS_ERROR_CORRUPTED_CONTENT);
|
||||
return CallOnStartRequest();
|
||||
@@ -2821,7 +2873,7 @@ nsHttpChannel::OpenCacheEntry(bool isHttps)
|
||||
}
|
||||
|
||||
if (!mPostID && mApplicationCache) {
|
||||
rv = cacheStorageService->AppCacheStorage(info,
|
||||
rv = cacheStorageService->AppCacheStorage(info,
|
||||
mApplicationCache,
|
||||
getter_AddRefs(cacheStorage));
|
||||
}
|
||||
@@ -5872,7 +5924,7 @@ nsHttpChannel::OnDataAvailable(nsIRequest *request, nsISupports *ctxt,
|
||||
}
|
||||
mLogicalOffset += count;
|
||||
}
|
||||
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
@@ -1247,6 +1247,12 @@
|
||||
"kind": "boolean",
|
||||
"description": "Whether a WAP content type response is served to the browser."
|
||||
},
|
||||
"HTTP_SCHEME_UPGRADE": {
|
||||
"expires_in_version": "never",
|
||||
"kind": "enumerated",
|
||||
"n_values": 10,
|
||||
"description": "Was the URL upgraded to HTTPS? (0=already HTTPS, 1=no reason to upgrade, 2=STS upgrade blocked by pref, 3=upgraded with STS, 4=upgraded with CSP)"
|
||||
},
|
||||
"SSL_HANDSHAKE_VERSION": {
|
||||
"expires_in_version": "never",
|
||||
"kind": "enumerated",
|
||||
|
||||
Reference in New Issue
Block a user