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:
2021-06-08 14:53:21 +08:00
parent ece7c7b7fe
commit 2da2bfc91b
43 changed files with 1644 additions and 212 deletions
+63 -34
View File
@@ -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
View File
@@ -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
View File
@@ -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;
-3
View File
@@ -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);
+8
View File
@@ -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;
+37
View File
@@ -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
//
+1 -2
View File
@@ -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).
+78
View File
@@ -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;
+4
View File
@@ -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
+13
View File
@@ -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)
{
+62 -9
View File
@@ -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);
+4
View File
@@ -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
View File
@@ -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
View File
@@ -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___ */
+21 -1
View File
@@ -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));
+13 -3
View File
@@ -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
+18
View File
@@ -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>
+1
View File
@@ -25,6 +25,7 @@ dictionary CSP {
sequence<DOMString> form-action;
sequence<DOMString> referrer;
sequence<DOMString> manifest-src;
sequence<DOMString> upgrade-insecure-requests;
};
dictionary CSPPolicies {
+1
View File
@@ -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);
+3
View File
@@ -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());
+42 -42
View File
@@ -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.
+2 -1
View File
@@ -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 {
+13
View File
@@ -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)
{
+9 -7
View File
@@ -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.
+22 -2
View File
@@ -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
+1
View File
@@ -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;
+57 -5
View File
@@ -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",