2015-05-03 22:32:37 +03:00
|
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
2014-04-01 20:35:22 +04:00
|
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
2018-01-16 23:59:00 +03:00
|
|
|
|
#include <string>
|
|
|
|
|
#include <unordered_set>
|
|
|
|
|
|
2014-04-01 20:35:22 +04:00
|
|
|
|
#include "nsCOMPtr.h"
|
|
|
|
|
#include "nsContentPolicyUtils.h"
|
|
|
|
|
#include "nsContentUtils.h"
|
|
|
|
|
#include "nsCSPContext.h"
|
|
|
|
|
#include "nsCSPParser.h"
|
|
|
|
|
#include "nsCSPService.h"
|
|
|
|
|
#include "nsError.h"
|
|
|
|
|
#include "nsIAsyncVerifyRedirectCallback.h"
|
2014-04-02 03:00:19 +04:00
|
|
|
|
#include "nsIClassInfoImpl.h"
|
2019-01-02 16:05:23 +03:00
|
|
|
|
#include "mozilla/dom/Document.h"
|
2014-04-01 20:35:22 +04:00
|
|
|
|
#include "nsIHttpChannel.h"
|
2014-05-21 01:59:51 +04:00
|
|
|
|
#include "nsIInterfaceRequestor.h"
|
2014-04-01 20:35:22 +04:00
|
|
|
|
#include "nsIInterfaceRequestorUtils.h"
|
2014-04-02 03:00:19 +04:00
|
|
|
|
#include "nsIObjectInputStream.h"
|
|
|
|
|
#include "nsIObjectOutputStream.h"
|
2014-04-01 20:35:22 +04:00
|
|
|
|
#include "nsIObserver.h"
|
|
|
|
|
#include "nsIObserverService.h"
|
2014-05-20 18:20:00 +04:00
|
|
|
|
#include "nsIStringStream.h"
|
2017-07-27 21:01:24 +03:00
|
|
|
|
#include "nsISupportsPrimitives.h"
|
2014-05-20 18:20:00 +04:00
|
|
|
|
#include "nsIUploadChannel.h"
|
2018-02-26 22:43:46 +03:00
|
|
|
|
#include "nsIURIMutator.h"
|
2014-04-01 20:35:22 +04:00
|
|
|
|
#include "nsIScriptError.h"
|
2015-08-19 18:42:05 +03:00
|
|
|
|
#include "nsMimeTypes.h"
|
2014-05-20 18:20:00 +04:00
|
|
|
|
#include "nsNetUtil.h"
|
2014-09-21 20:36:25 +04:00
|
|
|
|
#include "nsIContentPolicy.h"
|
2014-05-20 18:20:00 +04:00
|
|
|
|
#include "nsSupportsPrimitives.h"
|
|
|
|
|
#include "nsThreadUtils.h"
|
2014-04-01 20:35:22 +04:00
|
|
|
|
#include "nsString.h"
|
2015-07-27 21:57:56 +03:00
|
|
|
|
#include "nsScriptSecurityManager.h"
|
2015-08-19 18:42:05 +03:00
|
|
|
|
#include "nsStringStream.h"
|
2015-05-19 21:15:34 +03:00
|
|
|
|
#include "mozilla/Logging.h"
|
2017-11-07 01:01:32 +03:00
|
|
|
|
#include "mozilla/Preferences.h"
|
2014-08-04 23:51:10 +04:00
|
|
|
|
#include "mozilla/dom/CSPReportBinding.h"
|
2015-05-21 21:16:04 +03:00
|
|
|
|
#include "mozilla/dom/CSPDictionariesBinding.h"
|
2019-01-19 03:15:13 +03:00
|
|
|
|
#include "mozilla/ipc/PBackgroundSharedTypes.h"
|
2020-04-11 01:14:51 +03:00
|
|
|
|
#include "mozilla/dom/WindowGlobalParent.h"
|
2015-03-26 20:46:07 +03:00
|
|
|
|
#include "nsINetworkInterceptController.h"
|
2016-06-29 17:48:44 +03:00
|
|
|
|
#include "nsSandboxFlags.h"
|
2016-11-08 14:55:23 +03:00
|
|
|
|
#include "nsIScriptElement.h"
|
2017-03-29 05:20:32 +03:00
|
|
|
|
#include "nsIEventTarget.h"
|
|
|
|
|
#include "mozilla/dom/DocGroup.h"
|
2018-01-30 07:28:00 +03:00
|
|
|
|
#include "mozilla/dom/Element.h"
|
2017-03-29 05:20:32 +03:00
|
|
|
|
#include "nsXULAppAPI.h"
|
2019-07-22 12:31:57 +03:00
|
|
|
|
#include "nsJSUtils.h"
|
2014-04-01 20:35:22 +04:00
|
|
|
|
|
|
|
|
|
using namespace mozilla;
|
2018-07-10 18:40:21 +03:00
|
|
|
|
using namespace mozilla::dom;
|
2020-04-11 01:14:38 +03:00
|
|
|
|
using namespace mozilla::ipc;
|
2014-04-01 20:35:22 +04:00
|
|
|
|
|
2014-04-02 03:00:19 +04:00
|
|
|
|
static LogModule* GetCspContextLog() {
|
2015-11-23 22:09:25 +03:00
|
|
|
|
static LazyLogModule gCspContextPRLog("CSPContext");
|
2014-04-02 03:00:19 +04:00
|
|
|
|
return gCspContextPRLog;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-04 01:25:57 +03:00
|
|
|
|
#define CSPCONTEXTLOG(args) \
|
|
|
|
|
MOZ_LOG(GetCspContextLog(), mozilla::LogLevel::Debug, args)
|
|
|
|
|
#define CSPCONTEXTLOGENABLED() \
|
|
|
|
|
MOZ_LOG_TEST(GetCspContextLog(), mozilla::LogLevel::Debug)
|
2014-04-02 03:00:19 +04:00
|
|
|
|
|
2014-05-21 01:59:47 +04:00
|
|
|
|
static const uint32_t CSP_CACHE_URI_CUTOFF_SIZE = 512;
|
|
|
|
|
|
2018-01-16 23:59:00 +03:00
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
/**
|
|
|
|
|
* This function is only used for verification purposes within
|
|
|
|
|
* GatherSecurityPolicyViolationEventData.
|
|
|
|
|
*/
|
|
|
|
|
static bool ValidateDirectiveName(const nsAString& aDirective) {
|
|
|
|
|
static const auto directives = []() {
|
|
|
|
|
std::unordered_set<std::string> directives;
|
|
|
|
|
constexpr size_t dirLen =
|
|
|
|
|
sizeof(CSPStrDirectives) / sizeof(CSPStrDirectives[0]);
|
|
|
|
|
for (size_t i = 0; i < dirLen; ++i) {
|
|
|
|
|
directives.insert(CSPStrDirectives[i]);
|
|
|
|
|
}
|
|
|
|
|
return directives;
|
|
|
|
|
}();
|
|
|
|
|
|
|
|
|
|
nsAutoString directive(aDirective);
|
|
|
|
|
auto itr = directives.find(NS_ConvertUTF16toUTF8(directive).get());
|
|
|
|
|
return itr != directives.end();
|
|
|
|
|
}
|
|
|
|
|
#endif // DEBUG
|
|
|
|
|
|
2018-07-18 17:49:18 +03:00
|
|
|
|
static void BlockedContentSourceToString(
|
|
|
|
|
nsCSPContext::BlockedContentSource aSource, nsACString& aString) {
|
|
|
|
|
switch (aSource) {
|
|
|
|
|
case nsCSPContext::BlockedContentSource::eUnknown:
|
|
|
|
|
aString.Truncate();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case nsCSPContext::BlockedContentSource::eInline:
|
|
|
|
|
aString.AssignLiteral("inline");
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case nsCSPContext::BlockedContentSource::eEval:
|
|
|
|
|
aString.AssignLiteral("eval");
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case nsCSPContext::BlockedContentSource::eSelf:
|
|
|
|
|
aString.AssignLiteral("self");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-01 20:35:22 +04:00
|
|
|
|
/* ===== nsIContentSecurityPolicy impl ====== */
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
|
nsCSPContext::ShouldLoad(nsContentPolicyType aContentType,
|
2018-10-23 09:17:13 +03:00
|
|
|
|
nsICSPEventListener* aCSPEventListener,
|
2020-04-10 13:56:57 +03:00
|
|
|
|
nsIURI* aContentLocation,
|
2014-04-01 20:35:22 +04:00
|
|
|
|
const nsACString& aMimeTypeGuess,
|
2018-07-19 14:25:50 +03:00
|
|
|
|
nsIURI* aOriginalURIIfRedirect,
|
2019-02-13 22:45:29 +03:00
|
|
|
|
bool aSendViolationReports, const nsAString& aNonce,
|
2020-04-10 13:56:57 +03:00
|
|
|
|
bool aParserCreated, int16_t* outDecision) {
|
2015-05-12 00:22:04 +03:00
|
|
|
|
if (CSPCONTEXTLOGENABLED()) {
|
2016-08-26 09:02:31 +03:00
|
|
|
|
CSPCONTEXTLOG(("nsCSPContext::ShouldLoad, aContentLocation: %s",
|
|
|
|
|
aContentLocation->GetSpecOrDefault().get()));
|
2015-10-29 02:32:27 +03:00
|
|
|
|
CSPCONTEXTLOG((">>>> aContentType: %d", aContentType));
|
2014-04-02 03:00:19 +04:00
|
|
|
|
}
|
|
|
|
|
|
2015-11-15 06:29:18 +03:00
|
|
|
|
bool isPreload = nsContentUtils::IsPreloadType(aContentType);
|
2015-09-21 00:56:34 +03:00
|
|
|
|
|
|
|
|
|
// Since we know whether we are dealing with a preload, we have to convert
|
|
|
|
|
// the internal policytype ot the external policy type before moving on.
|
2015-10-29 02:32:27 +03:00
|
|
|
|
// We still need to know if this is a worker so child-src can handle that
|
|
|
|
|
// case correctly.
|
|
|
|
|
aContentType =
|
|
|
|
|
nsContentUtils::InternalContentPolicyTypeToExternalOrWorker(aContentType);
|
2015-09-21 00:56:34 +03:00
|
|
|
|
|
2014-04-02 03:00:19 +04:00
|
|
|
|
// This ShouldLoad function is called from nsCSPService::ShouldLoad,
|
|
|
|
|
// which already checked a number of things, including:
|
|
|
|
|
// * aContentLocation is not null; we can consume this without further checks
|
2020-06-03 02:15:13 +03:00
|
|
|
|
// * scheme is not a allowlisted scheme (about: chrome:, etc).
|
2014-04-02 03:00:19 +04:00
|
|
|
|
// * CSP is enabled
|
2020-06-03 02:15:13 +03:00
|
|
|
|
// * Content Type is not allowlisted (CSP Reports, TYPE_DOCUMENT, etc).
|
2014-04-02 03:00:19 +04:00
|
|
|
|
// * Fast Path for Apps
|
|
|
|
|
|
|
|
|
|
// Default decision, CSP can revise it if there's a policy to enforce
|
2014-04-01 20:35:22 +04:00
|
|
|
|
*outDecision = nsIContentPolicy::ACCEPT;
|
2014-04-02 03:00:19 +04:00
|
|
|
|
|
2014-12-10 15:54:00 +03:00
|
|
|
|
// If the content type doesn't map to a CSP directive, there's nothing for
|
|
|
|
|
// CSP to do.
|
|
|
|
|
CSPDirective dir = CSP_ContentTypeToDirective(aContentType);
|
|
|
|
|
if (dir == nsIContentSecurityPolicy::NO_DIRECTIVE) {
|
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool permitted =
|
2020-04-11 01:15:21 +03:00
|
|
|
|
permitsInternal(dir,
|
2018-07-10 18:40:21 +03:00
|
|
|
|
nullptr, // aTriggeringElement
|
2018-10-23 09:17:13 +03:00
|
|
|
|
aCSPEventListener, aContentLocation,
|
2019-02-13 22:45:29 +03:00
|
|
|
|
aOriginalURIIfRedirect, aNonce, isPreload,
|
2014-12-10 15:54:00 +03:00
|
|
|
|
false, // allow fallback to default-src
|
2018-08-01 07:35:24 +03:00
|
|
|
|
aSendViolationReports,
|
2016-11-08 14:55:23 +03:00
|
|
|
|
true, // send blocked URI in violation reports
|
2020-04-10 13:56:57 +03:00
|
|
|
|
aParserCreated);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
|
2014-12-10 15:54:00 +03:00
|
|
|
|
*outDecision =
|
|
|
|
|
permitted ? nsIContentPolicy::ACCEPT : nsIContentPolicy::REJECT_SERVER;
|
|
|
|
|
|
2015-05-12 00:22:04 +03:00
|
|
|
|
if (CSPCONTEXTLOGENABLED()) {
|
2016-08-26 09:02:31 +03:00
|
|
|
|
CSPCONTEXTLOG(
|
|
|
|
|
("nsCSPContext::ShouldLoad, decision: %s, "
|
|
|
|
|
"aContentLocation: %s",
|
|
|
|
|
*outDecision > 0 ? "load" : "deny",
|
|
|
|
|
aContentLocation->GetSpecOrDefault().get()));
|
2014-12-10 15:54:00 +03:00
|
|
|
|
}
|
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool nsCSPContext::permitsInternal(
|
2020-04-11 01:15:21 +03:00
|
|
|
|
CSPDirective aDir, Element* aTriggeringElement,
|
|
|
|
|
nsICSPEventListener* aCSPEventListener, nsIURI* aContentLocation,
|
|
|
|
|
nsIURI* aOriginalURIIfRedirect, const nsAString& aNonce, bool aIsPreload,
|
|
|
|
|
bool aSpecific, bool aSendViolationReports,
|
|
|
|
|
bool aSendContentLocationInViolationReports, bool aParserCreated) {
|
2020-04-11 01:13:45 +03:00
|
|
|
|
EnsureIPCPoliciesRead();
|
2014-12-10 15:54:00 +03:00
|
|
|
|
bool permits = true;
|
|
|
|
|
|
2014-04-02 03:00:19 +04:00
|
|
|
|
nsAutoString violatedDirective;
|
|
|
|
|
for (uint32_t p = 0; p < mPolicies.Length(); p++) {
|
2014-12-10 15:54:00 +03:00
|
|
|
|
if (!mPolicies[p]->permits(aDir, aContentLocation, aNonce,
|
2018-07-19 14:25:50 +03:00
|
|
|
|
!!aOriginalURIIfRedirect, aSpecific,
|
2014-04-02 03:00:19 +04:00
|
|
|
|
aParserCreated, violatedDirective)) {
|
|
|
|
|
// If the policy is violated and not report-only, reject the load and
|
|
|
|
|
// report to the console
|
|
|
|
|
if (!mPolicies[p]->getReportOnlyFlag()) {
|
2014-12-10 15:54:00 +03:00
|
|
|
|
CSPCONTEXTLOG(("nsCSPContext::permitsInternal, false"));
|
|
|
|
|
permits = false;
|
2014-04-02 03:00:19 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Do not send a report or notify observers if this is a preload - the
|
|
|
|
|
// decision may be wrong due to the inability to get the nonce, and will
|
|
|
|
|
// incorrectly fail the unit tests.
|
2014-12-10 15:54:00 +03:00
|
|
|
|
if (!aIsPreload && aSendViolationReports) {
|
2019-07-22 12:31:57 +03:00
|
|
|
|
uint32_t lineNumber = 0;
|
|
|
|
|
uint32_t columnNumber = 0;
|
2019-08-21 01:53:49 +03:00
|
|
|
|
nsAutoString spec;
|
2019-07-22 12:31:57 +03:00
|
|
|
|
JSContext* cx = nsContentUtils::GetCurrentJSContext();
|
|
|
|
|
if (cx) {
|
|
|
|
|
nsJSUtils::GetCallingLocation(cx, spec, &lineNumber, &columnNumber);
|
|
|
|
|
// If GetCallingLocation fails linenumber & columnNumber are set to 0
|
|
|
|
|
// anyway so we can skip checking if that is the case.
|
|
|
|
|
}
|
2020-04-11 01:15:21 +03:00
|
|
|
|
AsyncReportViolation(
|
|
|
|
|
aTriggeringElement, aCSPEventListener,
|
|
|
|
|
(aSendContentLocationInViolationReports ? aContentLocation
|
|
|
|
|
: nullptr),
|
|
|
|
|
BlockedContentSource::eUnknown, /* a BlockedContentSource */
|
|
|
|
|
aOriginalURIIfRedirect, /* in case of redirect originalURI is not
|
|
|
|
|
null */
|
|
|
|
|
violatedDirective, p, /* policy index */
|
|
|
|
|
EmptyString(), /* no observer subject */
|
|
|
|
|
spec, /* source file */
|
|
|
|
|
EmptyString(), /* no script sample */
|
|
|
|
|
lineNumber, /* line number */
|
|
|
|
|
columnNumber); /* column number */
|
2014-04-02 03:00:19 +04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-05-21 01:59:47 +04:00
|
|
|
|
|
2014-12-10 15:54:00 +03:00
|
|
|
|
return permits;
|
2014-04-01 20:35:22 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ===== nsISupports implementation ========== */
|
|
|
|
|
|
2014-04-02 03:00:19 +04:00
|
|
|
|
NS_IMPL_CLASSINFO(nsCSPContext, nullptr, nsIClassInfo::MAIN_THREAD_ONLY,
|
|
|
|
|
NS_CSPCONTEXT_CID)
|
|
|
|
|
|
|
|
|
|
NS_IMPL_ISUPPORTS_CI(nsCSPContext, nsIContentSecurityPolicy, nsISerializable)
|
2014-04-01 20:35:22 +04:00
|
|
|
|
|
|
|
|
|
nsCSPContext::nsCSPContext()
|
2015-07-27 21:57:56 +03:00
|
|
|
|
: mInnerWindowID(0),
|
2019-09-17 02:47:19 +03:00
|
|
|
|
mSkipAllowInlineStyleCheck(false),
|
2015-07-27 21:57:56 +03:00
|
|
|
|
mLoadingContext(nullptr),
|
|
|
|
|
mLoadingPrincipal(nullptr),
|
2015-11-11 17:23:57 +03:00
|
|
|
|
mQueueUpMessages(true) {
|
2014-04-02 03:00:19 +04:00
|
|
|
|
CSPCONTEXTLOG(("nsCSPContext::nsCSPContext"));
|
2014-04-01 20:35:22 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nsCSPContext::~nsCSPContext() {
|
2014-04-02 03:00:19 +04:00
|
|
|
|
CSPCONTEXTLOG(("nsCSPContext::~nsCSPContext"));
|
2014-04-01 20:35:22 +04:00
|
|
|
|
for (uint32_t i = 0; i < mPolicies.Length(); i++) {
|
|
|
|
|
delete mPolicies[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-15 15:20:52 +03:00
|
|
|
|
/* static */
|
|
|
|
|
bool nsCSPContext::Equals(nsIContentSecurityPolicy* aCSP,
|
|
|
|
|
nsIContentSecurityPolicy* aOtherCSP) {
|
|
|
|
|
if (aCSP == aOtherCSP) {
|
|
|
|
|
// fast path for pointer equality
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t policyCount = 0;
|
|
|
|
|
if (aCSP) {
|
|
|
|
|
aCSP->GetPolicyCount(&policyCount);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t otherPolicyCount = 0;
|
|
|
|
|
if (aOtherCSP) {
|
|
|
|
|
aOtherCSP->GetPolicyCount(&otherPolicyCount);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (policyCount != otherPolicyCount) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nsAutoString policyStr, otherPolicyStr;
|
|
|
|
|
for (uint32_t i = 0; i < policyCount; ++i) {
|
|
|
|
|
aCSP->GetPolicyString(i, policyStr);
|
|
|
|
|
aOtherCSP->GetPolicyString(i, otherPolicyStr);
|
|
|
|
|
if (!policyStr.Equals(otherPolicyStr)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-22 02:14:27 +03:00
|
|
|
|
nsresult nsCSPContext::InitFromOther(nsCSPContext* aOtherContext) {
|
2019-01-08 18:59:21 +03:00
|
|
|
|
NS_ENSURE_ARG(aOtherContext);
|
|
|
|
|
|
2019-05-22 02:14:27 +03:00
|
|
|
|
nsresult rv = NS_OK;
|
|
|
|
|
nsCOMPtr<Document> doc = do_QueryReferent(aOtherContext->mLoadingContext);
|
|
|
|
|
if (doc) {
|
|
|
|
|
rv = SetRequestContextWithDocument(doc);
|
|
|
|
|
} else {
|
|
|
|
|
rv = SetRequestContextWithPrincipal(
|
|
|
|
|
aOtherContext->mLoadingPrincipal, aOtherContext->mSelfURI,
|
|
|
|
|
aOtherContext->mReferrer, aOtherContext->mInnerWindowID);
|
|
|
|
|
}
|
2019-01-08 18:59:21 +03:00
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
2019-09-17 02:47:19 +03:00
|
|
|
|
mSkipAllowInlineStyleCheck = aOtherContext->mSkipAllowInlineStyleCheck;
|
|
|
|
|
|
2019-01-08 18:59:21 +03:00
|
|
|
|
for (auto policy : aOtherContext->mPolicies) {
|
|
|
|
|
nsAutoString policyStr;
|
|
|
|
|
policy->toString(policyStr);
|
|
|
|
|
AppendPolicy(policyStr, policy->getReportOnlyFlag(),
|
|
|
|
|
policy->getDeliveredViaMetaTagFlag());
|
|
|
|
|
}
|
2020-05-06 14:16:49 +03:00
|
|
|
|
mIPCPolicies = aOtherContext->mIPCPolicies.Clone();
|
2019-01-08 18:59:21 +03:00
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-19 03:15:13 +03:00
|
|
|
|
void nsCSPContext::EnsureIPCPoliciesRead() {
|
|
|
|
|
if (mIPCPolicies.Length() > 0) {
|
|
|
|
|
nsresult rv;
|
|
|
|
|
for (auto& policy : mIPCPolicies) {
|
|
|
|
|
rv = AppendPolicy(policy.policy(), policy.reportOnlyFlag(),
|
|
|
|
|
policy.deliveredViaMetaTagFlag());
|
|
|
|
|
Unused << NS_WARN_IF(NS_FAILED(rv));
|
|
|
|
|
}
|
|
|
|
|
mIPCPolicies.Clear();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-01 20:35:22 +04:00
|
|
|
|
NS_IMETHODIMP
|
2016-08-11 19:09:30 +03:00
|
|
|
|
nsCSPContext::GetPolicyString(uint32_t aIndex, nsAString& outStr) {
|
2018-11-23 18:05:24 +03:00
|
|
|
|
outStr.Truncate();
|
2019-01-19 03:15:13 +03:00
|
|
|
|
EnsureIPCPoliciesRead();
|
2014-04-01 20:35:22 +04:00
|
|
|
|
if (aIndex >= mPolicies.Length()) {
|
2014-04-02 03:00:19 +04:00
|
|
|
|
return NS_ERROR_ILLEGAL_VALUE;
|
2014-04-01 20:35:22 +04:00
|
|
|
|
}
|
|
|
|
|
mPolicies[aIndex]->toString(outStr);
|
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-24 06:42:43 +03:00
|
|
|
|
const nsCSPPolicy* nsCSPContext::GetPolicy(uint32_t aIndex) {
|
2019-01-19 03:15:13 +03:00
|
|
|
|
EnsureIPCPoliciesRead();
|
2016-04-24 06:42:43 +03:00
|
|
|
|
if (aIndex >= mPolicies.Length()) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
return mPolicies[aIndex];
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-01 20:35:22 +04:00
|
|
|
|
NS_IMETHODIMP
|
|
|
|
|
nsCSPContext::GetPolicyCount(uint32_t* outPolicyCount) {
|
2019-01-19 03:15:13 +03:00
|
|
|
|
EnsureIPCPoliciesRead();
|
2014-04-01 20:35:22 +04:00
|
|
|
|
*outPolicyCount = mPolicies.Length();
|
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-10 19:13:54 +03:00
|
|
|
|
NS_IMETHODIMP
|
|
|
|
|
nsCSPContext::GetUpgradeInsecureRequests(bool* outUpgradeRequest) {
|
2019-01-19 03:15:13 +03:00
|
|
|
|
EnsureIPCPoliciesRead();
|
2015-07-10 19:13:54 +03:00
|
|
|
|
*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;
|
|
|
|
|
}
|
2016-01-14 07:58:16 +03:00
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
|
nsCSPContext::GetBlockAllMixedContent(bool* outBlockAllMixedContent) {
|
2019-01-19 03:15:13 +03:00
|
|
|
|
EnsureIPCPoliciesRead();
|
2016-01-14 07:58:16 +03:00
|
|
|
|
*outBlockAllMixedContent = false;
|
|
|
|
|
for (uint32_t i = 0; i < mPolicies.Length(); i++) {
|
2016-08-24 10:24:55 +03:00
|
|
|
|
if (!mPolicies[i]->getReportOnlyFlag() &&
|
|
|
|
|
mPolicies[i]->hasDirective(
|
|
|
|
|
nsIContentSecurityPolicy::BLOCK_ALL_MIXED_CONTENT)) {
|
2016-01-14 07:58:16 +03:00
|
|
|
|
*outBlockAllMixedContent = true;
|
|
|
|
|
return NS_OK;
|
2017-06-07 22:17:49 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
|
nsCSPContext::GetEnforcesFrameAncestors(bool* outEnforcesFrameAncestors) {
|
2019-01-19 03:15:13 +03:00
|
|
|
|
EnsureIPCPoliciesRead();
|
2017-06-07 22:17:49 +03:00
|
|
|
|
*outEnforcesFrameAncestors = false;
|
|
|
|
|
for (uint32_t i = 0; i < mPolicies.Length(); i++) {
|
|
|
|
|
if (!mPolicies[i]->getReportOnlyFlag() &&
|
|
|
|
|
mPolicies[i]->hasDirective(
|
|
|
|
|
nsIContentSecurityPolicy::FRAME_ANCESTORS_DIRECTIVE)) {
|
|
|
|
|
*outEnforcesFrameAncestors = true;
|
|
|
|
|
return NS_OK;
|
2016-01-14 07:58:16 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
2015-07-10 19:13:54 +03:00
|
|
|
|
|
2014-04-01 20:35:22 +04:00
|
|
|
|
NS_IMETHODIMP
|
|
|
|
|
nsCSPContext::AppendPolicy(const nsAString& aPolicyString, bool aReportOnly,
|
2015-11-15 06:27:59 +03:00
|
|
|
|
bool aDeliveredViaMetaTag) {
|
2014-04-02 03:00:19 +04:00
|
|
|
|
CSPCONTEXTLOG(("nsCSPContext::AppendPolicy: %s",
|
|
|
|
|
NS_ConvertUTF16toUTF8(aPolicyString).get()));
|
|
|
|
|
|
2019-05-22 02:14:27 +03:00
|
|
|
|
// Use mSelfURI from setRequestContextWith{Document,Principal} (bug 991474)
|
|
|
|
|
MOZ_ASSERT(
|
|
|
|
|
mLoadingPrincipal,
|
|
|
|
|
"did you forget to call setRequestContextWith{Document,Principal}?");
|
|
|
|
|
MOZ_ASSERT(
|
|
|
|
|
mSelfURI,
|
|
|
|
|
"did you forget to call setRequestContextWith{Document,Principal}?");
|
|
|
|
|
NS_ENSURE_TRUE(mLoadingPrincipal, NS_ERROR_UNEXPECTED);
|
|
|
|
|
NS_ENSURE_TRUE(mSelfURI, NS_ERROR_UNEXPECTED);
|
|
|
|
|
|
2015-11-15 06:27:59 +03:00
|
|
|
|
nsCSPPolicy* policy = nsCSPParser::parseContentSecurityPolicy(
|
|
|
|
|
aPolicyString, mSelfURI, aReportOnly, this, aDeliveredViaMetaTag);
|
2014-04-01 20:35:22 +04:00
|
|
|
|
if (policy) {
|
2018-01-11 11:57:00 +03:00
|
|
|
|
if (policy->hasDirective(
|
|
|
|
|
nsIContentSecurityPolicy::UPGRADE_IF_INSECURE_DIRECTIVE)) {
|
|
|
|
|
nsAutoCString selfURIspec, referrer;
|
|
|
|
|
if (mSelfURI) {
|
|
|
|
|
mSelfURI->GetAsciiSpec(selfURIspec);
|
|
|
|
|
}
|
|
|
|
|
referrer = NS_ConvertUTF16toUTF8(mReferrer);
|
|
|
|
|
CSPCONTEXTLOG(
|
|
|
|
|
("nsCSPContext::AppendPolicy added UPGRADE_IF_INSECURE_DIRECTIVE "
|
|
|
|
|
"self-uri=%s referrer=%s",
|
|
|
|
|
selfURIspec.get(), referrer.get()));
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-01 20:35:22 +04:00
|
|
|
|
mPolicies.AppendElement(policy);
|
2019-03-14 09:26:29 +03:00
|
|
|
|
|
|
|
|
|
// set the flag on the document for CSP telemetry
|
|
|
|
|
nsCOMPtr<Document> doc = do_QueryReferent(mLoadingContext);
|
|
|
|
|
if (doc) {
|
|
|
|
|
doc->SetHasCSP(true);
|
|
|
|
|
}
|
2014-04-01 20:35:22 +04:00
|
|
|
|
}
|
2019-03-14 09:26:29 +03:00
|
|
|
|
|
2014-04-01 20:35:22 +04:00
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2015-09-18 08:34:16 +03:00
|
|
|
|
nsCSPContext::GetAllowsEval(bool* outShouldReportViolation,
|
|
|
|
|
bool* outAllowsEval) {
|
2019-01-19 03:15:13 +03:00
|
|
|
|
EnsureIPCPoliciesRead();
|
2014-04-02 03:00:19 +04:00
|
|
|
|
*outShouldReportViolation = false;
|
2015-09-18 08:34:16 +03:00
|
|
|
|
*outAllowsEval = true;
|
2014-04-02 03:00:19 +04:00
|
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < mPolicies.Length(); i++) {
|
2015-09-18 08:34:16 +03:00
|
|
|
|
if (!mPolicies[i]->allows(nsIContentPolicy::TYPE_SCRIPT, CSP_UNSAFE_EVAL,
|
2016-11-08 14:55:23 +03:00
|
|
|
|
EmptyString(), false)) {
|
2014-04-02 03:00:19 +04:00
|
|
|
|
// policy is violated: must report the violation and allow the inline
|
|
|
|
|
// script if the policy is report-only.
|
|
|
|
|
*outShouldReportViolation = true;
|
|
|
|
|
if (!mPolicies[i]->getReportOnlyFlag()) {
|
2015-09-18 08:34:16 +03:00
|
|
|
|
*outAllowsEval = false;
|
2014-04-02 03:00:19 +04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-18 08:34:16 +03:00
|
|
|
|
// Helper function to report inline violations
|
|
|
|
|
void nsCSPContext::reportInlineViolation(
|
|
|
|
|
nsContentPolicyType aContentType, Element* aTriggeringElement,
|
2018-10-23 09:17:13 +03:00
|
|
|
|
nsICSPEventListener* aCSPEventListener, const nsAString& aNonce,
|
2015-09-18 08:34:16 +03:00
|
|
|
|
const nsAString& aContent, const nsAString& aViolatedDirective,
|
|
|
|
|
uint32_t aViolatedPolicyIndex, // TODO, use report only flag for that
|
2018-07-05 09:21:04 +03:00
|
|
|
|
uint32_t aLineNumber, uint32_t aColumnNumber) {
|
2015-09-18 08:34:16 +03:00
|
|
|
|
nsString observerSubject;
|
|
|
|
|
// if the nonce is non empty, then we report the nonce error, otherwise
|
|
|
|
|
// let's report the hash error; no need to report the unsafe-inline error
|
|
|
|
|
// anymore.
|
|
|
|
|
if (!aNonce.IsEmpty()) {
|
2020-07-01 11:34:12 +03:00
|
|
|
|
observerSubject = (aContentType == nsIContentPolicy::TYPE_SCRIPT)
|
|
|
|
|
? NS_LITERAL_STRING_FROM_CSTRING(
|
|
|
|
|
SCRIPT_NONCE_VIOLATION_OBSERVER_TOPIC)
|
|
|
|
|
: NS_LITERAL_STRING_FROM_CSTRING(
|
|
|
|
|
STYLE_NONCE_VIOLATION_OBSERVER_TOPIC);
|
2015-09-18 08:34:16 +03:00
|
|
|
|
} else {
|
2020-07-01 11:34:12 +03:00
|
|
|
|
observerSubject = (aContentType == nsIContentPolicy::TYPE_SCRIPT)
|
|
|
|
|
? NS_LITERAL_STRING_FROM_CSTRING(
|
|
|
|
|
SCRIPT_HASH_VIOLATION_OBSERVER_TOPIC)
|
|
|
|
|
: NS_LITERAL_STRING_FROM_CSTRING(
|
|
|
|
|
STYLE_HASH_VIOLATION_OBSERVER_TOPIC);
|
2015-09-18 08:34:16 +03:00
|
|
|
|
}
|
2014-04-01 20:35:22 +04:00
|
|
|
|
|
2019-08-21 01:53:53 +03:00
|
|
|
|
nsAutoString sourceFile;
|
|
|
|
|
uint32_t lineNumber;
|
|
|
|
|
uint32_t columnNumber;
|
2019-07-22 12:31:57 +03:00
|
|
|
|
|
|
|
|
|
JSContext* cx = nsContentUtils::GetCurrentJSContext();
|
2019-08-21 01:53:53 +03:00
|
|
|
|
if (!cx || !nsJSUtils::GetCallingLocation(cx, sourceFile, &lineNumber,
|
|
|
|
|
&columnNumber)) {
|
|
|
|
|
// use selfURI as the sourceFile
|
|
|
|
|
if (mSelfURI) {
|
|
|
|
|
nsAutoCString cSourceFile;
|
|
|
|
|
mSelfURI->GetSpec(cSourceFile);
|
|
|
|
|
sourceFile.Assign(NS_ConvertUTF8toUTF16(cSourceFile));
|
2019-07-22 12:31:57 +03:00
|
|
|
|
}
|
2019-08-21 01:53:53 +03:00
|
|
|
|
lineNumber = aLineNumber;
|
|
|
|
|
columnNumber = aColumnNumber;
|
2019-07-22 12:31:57 +03:00
|
|
|
|
}
|
|
|
|
|
|
2020-04-11 01:15:21 +03:00
|
|
|
|
AsyncReportViolation(aTriggeringElement, aCSPEventListener,
|
2018-07-18 17:49:18 +03:00
|
|
|
|
nullptr, // aBlockedURI
|
2018-10-23 09:17:13 +03:00
|
|
|
|
BlockedContentSource::eInline, // aBlockedSource
|
2015-09-18 08:34:16 +03:00
|
|
|
|
mSelfURI, // aOriginalURI
|
|
|
|
|
aViolatedDirective, // aViolatedDirective
|
|
|
|
|
aViolatedPolicyIndex, // aViolatedPolicyIndex
|
|
|
|
|
observerSubject, // aObserverSubject
|
2019-08-21 01:53:53 +03:00
|
|
|
|
sourceFile, // aSourceFile
|
|
|
|
|
aContent, // aScriptSample
|
|
|
|
|
lineNumber, // aLineNum
|
|
|
|
|
columnNumber); // aColumnNum
|
2014-04-01 20:35:22 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2015-09-18 08:34:16 +03:00
|
|
|
|
nsCSPContext::GetAllowsInline(nsContentPolicyType aContentType,
|
|
|
|
|
const nsAString& aNonce, bool aParserCreated,
|
2018-07-10 18:40:21 +03:00
|
|
|
|
Element* aTriggeringElement,
|
2018-10-23 09:17:13 +03:00
|
|
|
|
nsICSPEventListener* aCSPEventListener,
|
2018-07-10 18:40:21 +03:00
|
|
|
|
const nsAString& aContentOfPseudoScript,
|
2018-07-05 09:21:04 +03:00
|
|
|
|
uint32_t aLineNumber, uint32_t aColumnNumber,
|
2015-09-18 08:34:16 +03:00
|
|
|
|
bool* outAllowsInline) {
|
|
|
|
|
*outAllowsInline = true;
|
|
|
|
|
|
|
|
|
|
MOZ_ASSERT(
|
|
|
|
|
aContentType ==
|
|
|
|
|
nsContentUtils::InternalContentPolicyTypeToExternal(aContentType),
|
|
|
|
|
"We should only see external content policy types here.");
|
|
|
|
|
|
|
|
|
|
if (aContentType != nsIContentPolicy::TYPE_SCRIPT &&
|
|
|
|
|
aContentType != nsIContentPolicy::TYPE_STYLESHEET) {
|
|
|
|
|
MOZ_ASSERT(false, "can only allow inline for script or style");
|
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-19 03:15:13 +03:00
|
|
|
|
EnsureIPCPoliciesRead();
|
2017-07-27 21:01:24 +03:00
|
|
|
|
nsAutoString content(EmptyString());
|
|
|
|
|
|
2015-09-18 08:34:16 +03:00
|
|
|
|
// always iterate all policies, otherwise we might not send out all reports
|
|
|
|
|
for (uint32_t i = 0; i < mPolicies.Length(); i++) {
|
|
|
|
|
bool allowed =
|
2016-11-08 14:55:23 +03:00
|
|
|
|
mPolicies[i]->allows(aContentType, CSP_UNSAFE_INLINE, EmptyString(),
|
|
|
|
|
aParserCreated) ||
|
2017-07-27 21:01:24 +03:00
|
|
|
|
mPolicies[i]->allows(aContentType, CSP_NONCE, aNonce, aParserCreated);
|
|
|
|
|
|
|
|
|
|
// If the inlined script or style is allowed by either unsafe-inline or the
|
|
|
|
|
// nonce, go ahead and shortcut this loop so we can avoid allocating
|
|
|
|
|
// unecessary strings
|
|
|
|
|
if (allowed) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check the content length to ensure the content is not allocated more than
|
|
|
|
|
// once. Even though we are in a for loop, it is probable that there is only
|
|
|
|
|
// one policy, so this check may be unnecessary.
|
2018-07-10 18:40:21 +03:00
|
|
|
|
if (content.IsEmpty() && aTriggeringElement) {
|
|
|
|
|
nsCOMPtr<nsIScriptElement> element =
|
|
|
|
|
do_QueryInterface(aTriggeringElement);
|
|
|
|
|
if (element) {
|
2017-07-27 21:01:24 +03:00
|
|
|
|
element->GetScriptText(content);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-16 15:23:08 +03:00
|
|
|
|
if (content.IsEmpty()) {
|
|
|
|
|
content = aContentOfPseudoScript;
|
2018-07-10 18:40:21 +03:00
|
|
|
|
}
|
2020-07-16 15:23:08 +03:00
|
|
|
|
allowed =
|
|
|
|
|
mPolicies[i]->allows(aContentType, CSP_HASH, content, aParserCreated);
|
2018-07-10 18:40:21 +03:00
|
|
|
|
|
2015-09-18 08:34:16 +03:00
|
|
|
|
if (!allowed) {
|
|
|
|
|
// policy is violoated: deny the load unless policy is report only and
|
|
|
|
|
// report the violation.
|
|
|
|
|
if (!mPolicies[i]->getReportOnlyFlag()) {
|
|
|
|
|
*outAllowsInline = false;
|
|
|
|
|
}
|
|
|
|
|
nsAutoString violatedDirective;
|
2018-07-06 09:01:49 +03:00
|
|
|
|
bool reportSample = false;
|
|
|
|
|
mPolicies[i]->getDirectiveStringAndReportSampleForContentType(
|
|
|
|
|
aContentType, violatedDirective, &reportSample);
|
2015-09-18 08:34:16 +03:00
|
|
|
|
reportInlineViolation(aContentType, aTriggeringElement, aCSPEventListener,
|
2018-07-06 09:01:49 +03:00
|
|
|
|
aNonce, reportSample ? content : EmptyString(),
|
2015-09-18 08:34:16 +03:00
|
|
|
|
violatedDirective, i, aLineNumber, aColumnNumber);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return NS_OK;
|
2014-04-01 20:35:22 +04:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-11 01:33:51 +03:00
|
|
|
|
NS_IMETHODIMP
|
2020-03-01 07:14:43 +03:00
|
|
|
|
nsCSPContext::GetAllowsNavigateTo(nsIURI* aURI, bool aIsFormSubmission,
|
2020-06-03 02:15:13 +03:00
|
|
|
|
bool aWasRedirected, bool aEnforceAllowlist,
|
2019-09-11 01:33:51 +03:00
|
|
|
|
bool* outAllowsNavigateTo) {
|
|
|
|
|
/*
|
|
|
|
|
* The matrix below shows the different values of (aWasRedirect,
|
2020-06-03 02:15:13 +03:00
|
|
|
|
* aEnforceAllowlist) for the three different checks we do.
|
2019-09-11 01:33:51 +03:00
|
|
|
|
*
|
|
|
|
|
* Navigation | Start Loading | Initiate Redirect | Document
|
|
|
|
|
* | (nsDocShell) | (nsCSPService) |
|
|
|
|
|
* -----------------------------------------------------------------
|
|
|
|
|
* A -> B (false,false) - (false,true)
|
|
|
|
|
* A -> ... -> B (false,false) (true,false) (true,true)
|
|
|
|
|
*/
|
|
|
|
|
*outAllowsNavigateTo = false;
|
|
|
|
|
|
|
|
|
|
EnsureIPCPoliciesRead();
|
|
|
|
|
// The 'form-action' directive overrules 'navigate-to' for form submissions.
|
|
|
|
|
// So in case this is a form submission and the directive 'form-action' is
|
|
|
|
|
// present then there is nothing for us to do here, see: 6.3.3.1.2
|
|
|
|
|
// https://www.w3.org/TR/CSP3/#navigate-to-pre-navigate
|
2020-03-01 07:14:43 +03:00
|
|
|
|
if (aIsFormSubmission) {
|
2019-09-11 01:33:51 +03:00
|
|
|
|
for (unsigned long i = 0; i < mPolicies.Length(); i++) {
|
|
|
|
|
if (mPolicies[i]->hasDirective(
|
|
|
|
|
nsIContentSecurityPolicy::FORM_ACTION_DIRECTIVE)) {
|
|
|
|
|
*outAllowsNavigateTo = true;
|
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool atLeastOneBlock = false;
|
|
|
|
|
for (unsigned long i = 0; i < mPolicies.Length(); i++) {
|
|
|
|
|
if (!mPolicies[i]->allowsNavigateTo(aURI, aWasRedirected,
|
2020-06-03 02:15:13 +03:00
|
|
|
|
aEnforceAllowlist)) {
|
2019-09-11 01:33:51 +03:00
|
|
|
|
if (!mPolicies[i]->getReportOnlyFlag()) {
|
|
|
|
|
atLeastOneBlock = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the load encountered a server side redirect, the spec suggests to
|
|
|
|
|
// remove the path component from the URI, see:
|
|
|
|
|
// https://www.w3.org/TR/CSP3/#source-list-paths-and-redirects
|
|
|
|
|
nsCOMPtr<nsIURI> blockedURIForReporting = aURI;
|
|
|
|
|
if (aWasRedirected) {
|
|
|
|
|
nsAutoCString prePathStr;
|
|
|
|
|
nsCOMPtr<nsIURI> prePathURI;
|
|
|
|
|
nsresult rv = aURI->GetPrePath(prePathStr);
|
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
rv = NS_NewURI(getter_AddRefs(blockedURIForReporting), prePathStr);
|
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Lines numbers and source file for the violation report
|
|
|
|
|
uint32_t lineNumber = 0;
|
|
|
|
|
uint32_t columnNumber = 0;
|
|
|
|
|
nsAutoCString spec;
|
|
|
|
|
JSContext* cx = nsContentUtils::GetCurrentJSContext();
|
|
|
|
|
if (cx) {
|
|
|
|
|
nsJSUtils::GetCallingLocation(cx, spec, &lineNumber, &columnNumber);
|
|
|
|
|
// If GetCallingLocation fails linenumber & columnNumber are set to 0
|
|
|
|
|
// anyway so we can skip checking if that is the case.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Report the violation
|
2020-04-11 01:15:21 +03:00
|
|
|
|
nsresult rv = AsyncReportViolation(
|
2019-09-11 01:33:51 +03:00
|
|
|
|
nullptr, // aTriggeringElement
|
|
|
|
|
nullptr, // aCSPEventListener
|
|
|
|
|
blockedURIForReporting, // aBlockedURI
|
|
|
|
|
nsCSPContext::BlockedContentSource::eSelf, // aBlockedSource
|
|
|
|
|
nullptr, // aOriginalURI
|
2020-07-01 11:29:29 +03:00
|
|
|
|
u"navigate-to"_ns, // aViolatedDirective
|
2019-09-11 01:33:51 +03:00
|
|
|
|
i, // aViolatedPolicyIndex
|
|
|
|
|
EmptyString(), // aObserverSubject
|
|
|
|
|
NS_ConvertUTF8toUTF16(spec), // aSourceFile
|
|
|
|
|
EmptyString(), // aScriptSample
|
|
|
|
|
lineNumber, // aLineNum
|
|
|
|
|
columnNumber); // aColumnNum
|
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*outAllowsNavigateTo = !atLeastOneBlock;
|
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-20 18:20:00 +04:00
|
|
|
|
/**
|
|
|
|
|
* Reduces some code repetition for the various logging situations in
|
|
|
|
|
* LogViolationDetails.
|
|
|
|
|
*
|
|
|
|
|
* Call-sites for the eval/inline checks recieve two return values: allows
|
|
|
|
|
* and violates. Based on those, they must choose whether to call
|
|
|
|
|
* LogViolationDetails or not. Policies that are report-only allow the
|
|
|
|
|
* loads/compilations but violations should still be reported. Not all
|
|
|
|
|
* policies in this nsIContentSecurityPolicy instance will be violated,
|
|
|
|
|
* which is why we must check allows() again here.
|
|
|
|
|
*
|
|
|
|
|
* Note: This macro uses some parameters from its caller's context:
|
2018-07-05 09:21:04 +03:00
|
|
|
|
* p, mPolicies, this, aSourceFile, aScriptSample, aLineNum, aColumnNum,
|
2018-07-18 17:49:18 +03:00
|
|
|
|
* blockedContentSource
|
2014-05-20 18:20:00 +04:00
|
|
|
|
*
|
|
|
|
|
* @param violationType: the VIOLATION_TYPE_* constant (partial symbol)
|
|
|
|
|
* such as INLINE_SCRIPT
|
2018-11-28 01:08:11 +03:00
|
|
|
|
* @param contentPolicyType: a constant from nsIContentPolicy such as
|
|
|
|
|
* TYPE_STYLESHEET
|
2014-05-20 18:20:00 +04:00
|
|
|
|
* @param nonceOrHash: for NONCE and HASH violations, it's the nonce or content
|
|
|
|
|
* string. For other violations, it is an empty string.
|
2018-11-28 01:08:11 +03:00
|
|
|
|
* @param keyword: the keyword corresponding to violation (UNSAFE_INLINE for
|
|
|
|
|
* most)
|
2014-05-20 18:20:00 +04:00
|
|
|
|
* @param observerTopic: the observer topic string to send with the CSP
|
|
|
|
|
* observer notifications.
|
2016-11-08 14:55:23 +03:00
|
|
|
|
*
|
|
|
|
|
* Please note that inline violations for scripts are reported within
|
|
|
|
|
* GetAllowsInline() and do not call this macro, hence we can pass 'false'
|
|
|
|
|
* as the argument _aParserCreated_ to allows().
|
2014-05-20 18:20:00 +04:00
|
|
|
|
*/
|
2020-07-01 11:34:12 +03:00
|
|
|
|
#define CASE_CHECK_AND_REPORT(violationType, contentPolicyType, nonceOrHash, \
|
|
|
|
|
keyword, observerTopic) \
|
|
|
|
|
case nsIContentSecurityPolicy::VIOLATION_TYPE_##violationType: \
|
|
|
|
|
PR_BEGIN_MACRO \
|
|
|
|
|
if (!mPolicies[p]->allows(nsIContentPolicy::TYPE_##contentPolicyType, \
|
|
|
|
|
keyword, nonceOrHash, false)) { \
|
|
|
|
|
nsAutoString violatedDirective; \
|
|
|
|
|
bool reportSample = false; \
|
|
|
|
|
mPolicies[p]->getDirectiveStringAndReportSampleForContentType( \
|
|
|
|
|
nsIContentPolicy::TYPE_##contentPolicyType, violatedDirective, \
|
|
|
|
|
&reportSample); \
|
|
|
|
|
AsyncReportViolation( \
|
|
|
|
|
aTriggeringElement, aCSPEventListener, nullptr, \
|
|
|
|
|
blockedContentSource, nullptr, violatedDirective, p, \
|
|
|
|
|
NS_LITERAL_STRING_FROM_CSTRING(observerTopic), aSourceFile, \
|
|
|
|
|
reportSample ? aScriptSample : EmptyString(), aLineNum, aColumnNum); \
|
|
|
|
|
} \
|
|
|
|
|
PR_END_MACRO; \
|
2014-05-20 18:20:00 +04:00
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* For each policy, log any violation on the Error Console and send a report
|
|
|
|
|
* if a report-uri is present in the policy
|
|
|
|
|
*
|
|
|
|
|
* @param aViolationType
|
|
|
|
|
* one of the VIOLATION_TYPE_* constants, e.g. inline-script or eval
|
|
|
|
|
* @param aSourceFile
|
|
|
|
|
* name of the source file containing the violation (if available)
|
|
|
|
|
* @param aContentSample
|
|
|
|
|
* sample of the violating content (to aid debugging)
|
|
|
|
|
* @param aLineNum
|
|
|
|
|
* source line number of the violation (if available)
|
2018-07-05 09:21:04 +03:00
|
|
|
|
* @param aColumnNum
|
|
|
|
|
* source column number of the violation (if available)
|
2014-05-20 18:20:00 +04:00
|
|
|
|
* @param aNonce
|
|
|
|
|
* (optional) If this is a nonce violation, include the nonce so we can
|
|
|
|
|
* recheck to determine which policies were violated and send the
|
|
|
|
|
* appropriate reports.
|
|
|
|
|
* @param aContent
|
|
|
|
|
* (optional) If this is a hash violation, include contents of the inline
|
|
|
|
|
* resource in the question so we can recheck the hash in order to
|
|
|
|
|
* determine which policies were violated and send the appropriate
|
|
|
|
|
* reports.
|
|
|
|
|
*/
|
2014-04-01 20:35:22 +04:00
|
|
|
|
NS_IMETHODIMP
|
|
|
|
|
nsCSPContext::LogViolationDetails(
|
2018-07-10 18:40:21 +03:00
|
|
|
|
uint16_t aViolationType, Element* aTriggeringElement,
|
2018-10-23 09:17:13 +03:00
|
|
|
|
nsICSPEventListener* aCSPEventListener, const nsAString& aSourceFile,
|
2014-04-01 20:35:22 +04:00
|
|
|
|
const nsAString& aScriptSample, int32_t aLineNum, int32_t aColumnNum,
|
|
|
|
|
const nsAString& aNonce, const nsAString& aContent) {
|
2019-01-19 03:15:13 +03:00
|
|
|
|
EnsureIPCPoliciesRead();
|
2014-05-20 18:20:00 +04:00
|
|
|
|
for (uint32_t p = 0; p < mPolicies.Length(); p++) {
|
|
|
|
|
NS_ASSERTION(mPolicies[p], "null pointer in nsTArray<nsCSPPolicy>");
|
|
|
|
|
|
2018-07-18 17:49:18 +03:00
|
|
|
|
BlockedContentSource blockedContentSource = BlockedContentSource::eUnknown;
|
|
|
|
|
if (aViolationType == nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL) {
|
|
|
|
|
blockedContentSource = BlockedContentSource::eEval;
|
|
|
|
|
} else if (aViolationType ==
|
|
|
|
|
nsIContentSecurityPolicy::VIOLATION_TYPE_INLINE_SCRIPT ||
|
|
|
|
|
aViolationType ==
|
|
|
|
|
nsIContentSecurityPolicy::VIOLATION_TYPE_INLINE_STYLE) {
|
|
|
|
|
blockedContentSource = BlockedContentSource::eInline;
|
|
|
|
|
} else {
|
|
|
|
|
// All the other types should have a URL, but just in case, let's use
|
|
|
|
|
// 'self' here.
|
|
|
|
|
blockedContentSource = BlockedContentSource::eSelf;
|
2014-05-20 18:20:00 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (aViolationType) {
|
2020-07-01 11:29:29 +03:00
|
|
|
|
CASE_CHECK_AND_REPORT(EVAL, SCRIPT, u""_ns, CSP_UNSAFE_EVAL,
|
|
|
|
|
EVAL_VIOLATION_OBSERVER_TOPIC);
|
|
|
|
|
CASE_CHECK_AND_REPORT(INLINE_STYLE, STYLESHEET, u""_ns, CSP_UNSAFE_INLINE,
|
2014-05-20 18:20:00 +04:00
|
|
|
|
INLINE_STYLE_VIOLATION_OBSERVER_TOPIC);
|
2020-07-01 11:29:29 +03:00
|
|
|
|
CASE_CHECK_AND_REPORT(INLINE_SCRIPT, SCRIPT, u""_ns, CSP_UNSAFE_INLINE,
|
2014-05-20 18:20:00 +04:00
|
|
|
|
INLINE_SCRIPT_VIOLATION_OBSERVER_TOPIC);
|
|
|
|
|
CASE_CHECK_AND_REPORT(NONCE_SCRIPT, SCRIPT, aNonce, CSP_UNSAFE_INLINE,
|
|
|
|
|
SCRIPT_NONCE_VIOLATION_OBSERVER_TOPIC);
|
|
|
|
|
CASE_CHECK_AND_REPORT(NONCE_STYLE, STYLESHEET, aNonce, CSP_UNSAFE_INLINE,
|
|
|
|
|
STYLE_NONCE_VIOLATION_OBSERVER_TOPIC);
|
|
|
|
|
CASE_CHECK_AND_REPORT(HASH_SCRIPT, SCRIPT, aContent, CSP_UNSAFE_INLINE,
|
|
|
|
|
SCRIPT_HASH_VIOLATION_OBSERVER_TOPIC);
|
|
|
|
|
CASE_CHECK_AND_REPORT(HASH_STYLE, STYLESHEET, aContent, CSP_UNSAFE_INLINE,
|
|
|
|
|
STYLE_HASH_VIOLATION_OBSERVER_TOPIC);
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
NS_ASSERTION(false, "LogViolationDetails with invalid type");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#undef CASE_CHECK_AND_REPORT
|
|
|
|
|
|
2014-04-01 20:35:22 +04:00
|
|
|
|
NS_IMETHODIMP
|
2019-05-22 02:14:27 +03:00
|
|
|
|
nsCSPContext::SetRequestContextWithDocument(Document* aDocument) {
|
|
|
|
|
MOZ_ASSERT(aDocument, "Can't set context without doc");
|
|
|
|
|
NS_ENSURE_ARG(aDocument);
|
|
|
|
|
|
|
|
|
|
mLoadingContext = do_GetWeakReference(aDocument);
|
|
|
|
|
mSelfURI = aDocument->GetDocumentURI();
|
|
|
|
|
mLoadingPrincipal = aDocument->NodePrincipal();
|
|
|
|
|
aDocument->GetReferrer(mReferrer);
|
|
|
|
|
mInnerWindowID = aDocument->InnerWindowID();
|
|
|
|
|
// the innerWindowID is not available for CSPs delivered through the
|
|
|
|
|
// header at the time setReqeustContext is called - let's queue up
|
|
|
|
|
// console messages until it becomes available, see flushConsoleMessages
|
|
|
|
|
mQueueUpMessages = !mInnerWindowID;
|
|
|
|
|
mCallingChannelLoadGroup = aDocument->GetDocumentLoadGroup();
|
|
|
|
|
// set the flag on the document for CSP telemetry
|
|
|
|
|
mEventTarget = aDocument->EventTargetFor(TaskCategory::Other);
|
|
|
|
|
|
|
|
|
|
MOZ_ASSERT(mLoadingPrincipal, "need a valid requestPrincipal");
|
|
|
|
|
MOZ_ASSERT(mSelfURI, "need mSelfURI to translate 'self' into actual URI");
|
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
2014-04-02 03:00:19 +04:00
|
|
|
|
|
2019-05-22 02:14:27 +03:00
|
|
|
|
NS_IMETHODIMP
|
|
|
|
|
nsCSPContext::SetRequestContextWithPrincipal(nsIPrincipal* aRequestPrincipal,
|
|
|
|
|
nsIURI* aSelfURI,
|
|
|
|
|
const nsAString& aReferrer,
|
|
|
|
|
uint64_t aInnerWindowId) {
|
|
|
|
|
NS_ENSURE_ARG(aRequestPrincipal);
|
|
|
|
|
|
|
|
|
|
mLoadingPrincipal = aRequestPrincipal;
|
|
|
|
|
mSelfURI = aSelfURI;
|
|
|
|
|
mReferrer = aReferrer;
|
|
|
|
|
mInnerWindowID = aInnerWindowId;
|
|
|
|
|
// if no document is available, then it also does not make sense to queue
|
|
|
|
|
// console messages sending messages to the browser console instead of the web
|
|
|
|
|
// console in that case.
|
|
|
|
|
mQueueUpMessages = false;
|
|
|
|
|
mCallingChannelLoadGroup = nullptr;
|
|
|
|
|
mEventTarget = nullptr;
|
|
|
|
|
|
|
|
|
|
MOZ_ASSERT(mLoadingPrincipal, "need a valid requestPrincipal");
|
|
|
|
|
MOZ_ASSERT(mSelfURI, "need mSelfURI to translate 'self' into actual URI");
|
2014-04-02 03:00:19 +04:00
|
|
|
|
return NS_OK;
|
2014-04-01 20:35:22 +04:00
|
|
|
|
}
|
|
|
|
|
|
2019-05-22 02:14:27 +03:00
|
|
|
|
nsIPrincipal* nsCSPContext::GetRequestPrincipal() { return mLoadingPrincipal; }
|
|
|
|
|
|
|
|
|
|
nsIURI* nsCSPContext::GetSelfURI() { return mSelfURI; }
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
|
nsCSPContext::GetReferrer(nsAString& outReferrer) {
|
|
|
|
|
outReferrer.Truncate();
|
|
|
|
|
outReferrer.Append(mReferrer);
|
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint64_t nsCSPContext::GetInnerWindowID() { return mInnerWindowID; }
|
|
|
|
|
|
2019-09-17 02:47:19 +03:00
|
|
|
|
bool nsCSPContext::GetSkipAllowInlineStyleCheck() {
|
|
|
|
|
return mSkipAllowInlineStyleCheck;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void nsCSPContext::SetSkipAllowInlineStyleCheck(
|
|
|
|
|
bool aSkipAllowInlineStyleCheck) {
|
|
|
|
|
mSkipAllowInlineStyleCheck = aSkipAllowInlineStyleCheck;
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-29 05:20:32 +03:00
|
|
|
|
NS_IMETHODIMP
|
|
|
|
|
nsCSPContext::EnsureEventTarget(nsIEventTarget* aEventTarget) {
|
|
|
|
|
NS_ENSURE_ARG(aEventTarget);
|
|
|
|
|
// Don't bother if we did have a valid event target (if the csp object is
|
2019-05-22 02:14:27 +03:00
|
|
|
|
// tied to a document in SetRequestContextWithDocument)
|
2017-03-29 05:20:32 +03:00
|
|
|
|
if (mEventTarget) {
|
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mEventTarget = aEventTarget;
|
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-11 17:23:57 +03:00
|
|
|
|
struct ConsoleMsgQueueElem {
|
2017-08-11 11:31:22 +03:00
|
|
|
|
nsString mMsg;
|
2015-11-11 17:23:57 +03:00
|
|
|
|
nsString mSourceName;
|
|
|
|
|
nsString mSourceLine;
|
|
|
|
|
uint32_t mLineNumber;
|
|
|
|
|
uint32_t mColumnNumber;
|
|
|
|
|
uint32_t mSeverityFlag;
|
2018-07-20 20:57:21 +03:00
|
|
|
|
nsCString mCategory;
|
2015-11-11 17:23:57 +03:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void nsCSPContext::flushConsoleMessages() {
|
2018-03-13 08:40:38 +03:00
|
|
|
|
bool privateWindow = false;
|
|
|
|
|
|
2015-11-11 17:23:57 +03:00
|
|
|
|
// should flush messages even if doc is not available
|
2019-01-02 16:05:23 +03:00
|
|
|
|
nsCOMPtr<Document> doc = do_QueryReferent(mLoadingContext);
|
2015-11-11 17:23:57 +03:00
|
|
|
|
if (doc) {
|
|
|
|
|
mInnerWindowID = doc->InnerWindowID();
|
2018-03-13 08:40:38 +03:00
|
|
|
|
privateWindow =
|
|
|
|
|
!!doc->NodePrincipal()->OriginAttributesRef().mPrivateBrowsingId;
|
2015-11-11 17:23:57 +03:00
|
|
|
|
}
|
2018-03-13 08:40:38 +03:00
|
|
|
|
|
2015-11-11 17:23:57 +03:00
|
|
|
|
mQueueUpMessages = false;
|
|
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < mConsoleMsgQueue.Length(); i++) {
|
|
|
|
|
ConsoleMsgQueueElem& elem = mConsoleMsgQueue[i];
|
|
|
|
|
CSP_LogMessage(elem.mMsg, elem.mSourceName, elem.mSourceLine,
|
|
|
|
|
elem.mLineNumber, elem.mColumnNumber, elem.mSeverityFlag,
|
2018-07-20 20:57:21 +03:00
|
|
|
|
elem.mCategory, mInnerWindowID, privateWindow);
|
2015-11-11 17:23:57 +03:00
|
|
|
|
}
|
|
|
|
|
mConsoleMsgQueue.Clear();
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-11 18:51:51 +03:00
|
|
|
|
void nsCSPContext::logToConsole(const char* aName,
|
|
|
|
|
const nsTArray<nsString>& aParams,
|
2015-11-11 17:23:57 +03:00
|
|
|
|
const nsAString& aSourceName,
|
|
|
|
|
const nsAString& aSourceLine,
|
|
|
|
|
uint32_t aLineNumber, uint32_t aColumnNumber,
|
|
|
|
|
uint32_t aSeverityFlag) {
|
2018-07-20 20:57:21 +03:00
|
|
|
|
// we are passing aName as the category so we can link to the
|
|
|
|
|
// appropriate MDN docs depending on the specific error.
|
|
|
|
|
nsDependentCString category(aName);
|
|
|
|
|
|
2015-11-11 17:23:57 +03:00
|
|
|
|
// let's check if we have to queue up console messages
|
|
|
|
|
if (mQueueUpMessages) {
|
2017-08-04 07:40:52 +03:00
|
|
|
|
nsAutoString msg;
|
2019-06-11 18:51:51 +03:00
|
|
|
|
CSP_GetLocalizedStr(aName, aParams, msg);
|
2015-11-11 17:23:57 +03:00
|
|
|
|
ConsoleMsgQueueElem& elem = *mConsoleMsgQueue.AppendElement();
|
|
|
|
|
elem.mMsg = msg;
|
|
|
|
|
elem.mSourceName = PromiseFlatString(aSourceName);
|
|
|
|
|
elem.mSourceLine = PromiseFlatString(aSourceLine);
|
|
|
|
|
elem.mLineNumber = aLineNumber;
|
|
|
|
|
elem.mColumnNumber = aColumnNumber;
|
|
|
|
|
elem.mSeverityFlag = aSeverityFlag;
|
2018-07-20 20:57:21 +03:00
|
|
|
|
elem.mCategory = category;
|
2015-11-11 17:23:57 +03:00
|
|
|
|
return;
|
|
|
|
|
}
|
2018-03-13 08:40:38 +03:00
|
|
|
|
|
|
|
|
|
bool privateWindow = false;
|
2019-01-02 16:05:23 +03:00
|
|
|
|
nsCOMPtr<Document> doc = do_QueryReferent(mLoadingContext);
|
2018-03-13 08:40:38 +03:00
|
|
|
|
if (doc) {
|
|
|
|
|
privateWindow =
|
|
|
|
|
!!doc->NodePrincipal()->OriginAttributesRef().mPrivateBrowsingId;
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-11 18:51:51 +03:00
|
|
|
|
CSP_LogLocalizedStr(aName, aParams, aSourceName, aSourceLine, aLineNumber,
|
|
|
|
|
aColumnNumber, aSeverityFlag, category, mInnerWindowID,
|
|
|
|
|
privateWindow);
|
2015-11-11 17:23:57 +03:00
|
|
|
|
}
|
|
|
|
|
|
2016-01-14 23:36:50 +03:00
|
|
|
|
/**
|
|
|
|
|
* Strip URI for reporting according to:
|
|
|
|
|
* http://www.w3.org/TR/CSP/#violation-reports
|
|
|
|
|
*
|
|
|
|
|
* @param aURI
|
|
|
|
|
* The uri to be stripped for reporting
|
2016-08-27 09:30:43 +03:00
|
|
|
|
* @param aSelfURI
|
|
|
|
|
* The uri of the protected resource
|
2016-01-14 23:36:50 +03:00
|
|
|
|
* which is needed to enforce the SOP.
|
|
|
|
|
* @return ASCII serialization of the uri to be reported.
|
|
|
|
|
*/
|
|
|
|
|
void StripURIForReporting(nsIURI* aURI, nsIURI* aSelfURI,
|
|
|
|
|
nsACString& outStrippedURI) {
|
|
|
|
|
// 1) If the origin of uri is a globally unique identifier (for example,
|
|
|
|
|
// aURI has a scheme of data, blob, or filesystem), then return the
|
|
|
|
|
// ASCII serialization of uri’s scheme.
|
2018-11-13 22:29:54 +03:00
|
|
|
|
bool isHttpFtpOrWs =
|
2019-07-30 10:23:18 +03:00
|
|
|
|
(aURI->SchemeIs("http") || aURI->SchemeIs("https") ||
|
|
|
|
|
aURI->SchemeIs("ftp") || aURI->SchemeIs("ws") || aURI->SchemeIs("wss"));
|
2018-11-13 22:29:54 +03:00
|
|
|
|
|
|
|
|
|
if (!isHttpFtpOrWs) {
|
2016-01-14 23:36:50 +03:00
|
|
|
|
// not strictly spec compliant, but what we really care about is
|
2016-04-17 21:09:18 +03:00
|
|
|
|
// http/https and also ftp. If it's not http/https or ftp, then treat aURI
|
|
|
|
|
// as if it's a globally unique identifier and just return the scheme.
|
2016-01-14 23:36:50 +03:00
|
|
|
|
aURI->GetScheme(outStrippedURI);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-18 17:49:18 +03:00
|
|
|
|
// Return uri, with any fragment component removed.
|
2016-01-14 23:36:50 +03:00
|
|
|
|
aURI->GetSpecIgnoringRef(outStrippedURI);
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-29 17:53:00 +03:00
|
|
|
|
nsresult nsCSPContext::GatherSecurityPolicyViolationEventData(
|
2018-07-17 12:13:12 +03:00
|
|
|
|
nsIURI* aBlockedURI, const nsACString& aBlockedString, nsIURI* aOriginalURI,
|
2017-11-29 17:53:00 +03:00
|
|
|
|
nsAString& aViolatedDirective, uint32_t aViolatedPolicyIndex,
|
|
|
|
|
nsAString& aSourceFile, nsAString& aScriptSample, uint32_t aLineNum,
|
2018-07-05 09:21:04 +03:00
|
|
|
|
uint32_t aColumnNum,
|
2017-11-29 17:53:00 +03:00
|
|
|
|
mozilla::dom::SecurityPolicyViolationEventInit& aViolationEventInit) {
|
2019-01-19 03:15:13 +03:00
|
|
|
|
EnsureIPCPoliciesRead();
|
2014-05-20 18:20:00 +04:00
|
|
|
|
NS_ENSURE_ARG_MAX(aViolatedPolicyIndex, mPolicies.Length() - 1);
|
|
|
|
|
|
2018-01-16 23:59:00 +03:00
|
|
|
|
MOZ_ASSERT(ValidateDirectiveName(aViolatedDirective),
|
|
|
|
|
"Invalid directive name");
|
|
|
|
|
|
2014-05-20 18:20:00 +04:00
|
|
|
|
nsresult rv;
|
|
|
|
|
|
2017-11-29 17:53:00 +03:00
|
|
|
|
// document-uri
|
|
|
|
|
nsAutoCString reportDocumentURI;
|
|
|
|
|
StripURIForReporting(mSelfURI, mSelfURI, reportDocumentURI);
|
|
|
|
|
aViolationEventInit.mDocumentURI = NS_ConvertUTF8toUTF16(reportDocumentURI);
|
|
|
|
|
|
|
|
|
|
// referrer
|
|
|
|
|
aViolationEventInit.mReferrer = mReferrer;
|
|
|
|
|
|
2014-05-20 18:20:00 +04:00
|
|
|
|
// blocked-uri
|
2018-03-09 03:23:03 +03:00
|
|
|
|
if (aBlockedURI) {
|
2020-05-16 19:57:00 +03:00
|
|
|
|
// in case of blocking a browsing context (frame) we have to report
|
|
|
|
|
// the final URI in case of a redirect. For subresources we report
|
|
|
|
|
// the URI before redirects.
|
|
|
|
|
nsCOMPtr<nsIURI> uriToReport;
|
|
|
|
|
if (aViolatedDirective.EqualsLiteral("frame-src")) {
|
|
|
|
|
uriToReport = aBlockedURI;
|
|
|
|
|
} else {
|
|
|
|
|
uriToReport = aOriginalURI ? aOriginalURI : aBlockedURI;
|
|
|
|
|
}
|
2014-05-20 18:20:00 +04:00
|
|
|
|
nsAutoCString reportBlockedURI;
|
2020-05-16 19:57:00 +03:00
|
|
|
|
StripURIForReporting(uriToReport, mSelfURI, reportBlockedURI);
|
2017-11-29 17:53:00 +03:00
|
|
|
|
aViolationEventInit.mBlockedURI = NS_ConvertUTF8toUTF16(reportBlockedURI);
|
2018-07-17 12:13:12 +03:00
|
|
|
|
} else {
|
|
|
|
|
aViolationEventInit.mBlockedURI = NS_ConvertUTF8toUTF16(aBlockedString);
|
2014-05-20 18:20:00 +04:00
|
|
|
|
}
|
2016-11-09 13:31:38 +03:00
|
|
|
|
|
2018-01-16 14:02:32 +03:00
|
|
|
|
// effective-directive
|
2018-01-16 23:59:00 +03:00
|
|
|
|
// The name of the policy directive that was violated.
|
2018-01-16 14:02:32 +03:00
|
|
|
|
aViolationEventInit.mEffectiveDirective = aViolatedDirective;
|
|
|
|
|
|
2018-01-16 23:59:00 +03:00
|
|
|
|
// violated-directive
|
|
|
|
|
// In CSP2, the policy directive that was violated, as it appears in the
|
|
|
|
|
// policy. In CSP3, the same as effective-directive.
|
|
|
|
|
aViolationEventInit.mViolatedDirective = aViolatedDirective;
|
|
|
|
|
|
2014-05-20 18:20:00 +04:00
|
|
|
|
// original-policy
|
|
|
|
|
nsAutoString originalPolicy;
|
2016-08-11 19:09:30 +03:00
|
|
|
|
rv = this->GetPolicyString(aViolatedPolicyIndex, originalPolicy);
|
2014-05-20 18:20:00 +04:00
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2017-11-29 17:53:00 +03:00
|
|
|
|
aViolationEventInit.mOriginalPolicy = originalPolicy;
|
2014-05-20 18:20:00 +04:00
|
|
|
|
|
|
|
|
|
// source-file
|
|
|
|
|
if (!aSourceFile.IsEmpty()) {
|
2014-08-06 03:12:16 +04:00
|
|
|
|
// if aSourceFile is a URI, we have to make sure to strip fragments
|
|
|
|
|
nsCOMPtr<nsIURI> sourceURI;
|
|
|
|
|
NS_NewURI(getter_AddRefs(sourceURI), aSourceFile);
|
|
|
|
|
if (sourceURI) {
|
|
|
|
|
nsAutoCString spec;
|
|
|
|
|
sourceURI->GetSpecIgnoringRef(spec);
|
|
|
|
|
aSourceFile = NS_ConvertUTF8toUTF16(spec);
|
|
|
|
|
}
|
2017-11-29 17:53:00 +03:00
|
|
|
|
aViolationEventInit.mSourceFile = aSourceFile;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-16 18:58:04 +03:00
|
|
|
|
// sample, max 40 chars.
|
2017-11-29 17:53:00 +03:00
|
|
|
|
aViolationEventInit.mSample = aScriptSample;
|
2018-07-16 18:58:04 +03:00
|
|
|
|
uint32_t length = aViolationEventInit.mSample.Length();
|
|
|
|
|
if (length > ScriptSampleMaxLength()) {
|
|
|
|
|
uint32_t desiredLength = ScriptSampleMaxLength();
|
|
|
|
|
// Don't cut off right before a low surrogate. Just include it.
|
|
|
|
|
if (NS_IS_LOW_SURROGATE(aViolationEventInit.mSample[desiredLength])) {
|
|
|
|
|
desiredLength++;
|
|
|
|
|
}
|
|
|
|
|
aViolationEventInit.mSample.Replace(ScriptSampleMaxLength(),
|
|
|
|
|
length - desiredLength,
|
|
|
|
|
nsContentUtils::GetLocalizedEllipsis());
|
|
|
|
|
}
|
2017-11-29 17:53:00 +03:00
|
|
|
|
|
|
|
|
|
// disposition
|
|
|
|
|
aViolationEventInit.mDisposition =
|
|
|
|
|
mPolicies[aViolatedPolicyIndex]->getReportOnlyFlag()
|
|
|
|
|
? mozilla::dom::SecurityPolicyViolationEventDisposition::Report
|
|
|
|
|
: mozilla::dom::SecurityPolicyViolationEventDisposition::Enforce;
|
|
|
|
|
|
|
|
|
|
// status-code
|
|
|
|
|
uint16_t statusCode = 0;
|
|
|
|
|
{
|
2019-01-02 16:05:23 +03:00
|
|
|
|
nsCOMPtr<Document> doc = do_QueryReferent(mLoadingContext);
|
2017-11-29 17:53:00 +03:00
|
|
|
|
if (doc) {
|
|
|
|
|
nsCOMPtr<nsIHttpChannel> channel = do_QueryInterface(doc->GetChannel());
|
|
|
|
|
if (channel) {
|
|
|
|
|
uint32_t responseStatus = 0;
|
|
|
|
|
nsresult rv = channel->GetResponseStatus(&responseStatus);
|
|
|
|
|
if (NS_SUCCEEDED(rv) && (responseStatus <= UINT16_MAX)) {
|
|
|
|
|
statusCode = static_cast<uint16_t>(responseStatus);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
aViolationEventInit.mStatusCode = statusCode;
|
|
|
|
|
|
|
|
|
|
// line-number
|
|
|
|
|
aViolationEventInit.mLineNumber = aLineNum;
|
|
|
|
|
|
|
|
|
|
// column-number
|
2018-07-05 09:21:04 +03:00
|
|
|
|
aViolationEventInit.mColumnNumber = aColumnNum;
|
2017-11-29 17:53:00 +03:00
|
|
|
|
|
|
|
|
|
aViolationEventInit.mBubbles = true;
|
|
|
|
|
aViolationEventInit.mComposed = true;
|
|
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nsresult nsCSPContext::SendReports(
|
|
|
|
|
const mozilla::dom::SecurityPolicyViolationEventInit& aViolationEventInit,
|
|
|
|
|
uint32_t aViolatedPolicyIndex) {
|
2019-01-19 03:15:13 +03:00
|
|
|
|
EnsureIPCPoliciesRead();
|
2017-11-29 17:53:00 +03:00
|
|
|
|
NS_ENSURE_ARG_MAX(aViolatedPolicyIndex, mPolicies.Length() - 1);
|
|
|
|
|
|
|
|
|
|
dom::CSPReport report;
|
|
|
|
|
|
|
|
|
|
// blocked-uri
|
|
|
|
|
report.mCsp_report.mBlocked_uri = aViolationEventInit.mBlockedURI;
|
|
|
|
|
|
|
|
|
|
// document-uri
|
|
|
|
|
report.mCsp_report.mDocument_uri = aViolationEventInit.mDocumentURI;
|
|
|
|
|
|
|
|
|
|
// original-policy
|
|
|
|
|
report.mCsp_report.mOriginal_policy = aViolationEventInit.mOriginalPolicy;
|
|
|
|
|
|
|
|
|
|
// referrer
|
|
|
|
|
report.mCsp_report.mReferrer = aViolationEventInit.mReferrer;
|
|
|
|
|
|
|
|
|
|
// violated-directive
|
|
|
|
|
report.mCsp_report.mViolated_directive =
|
|
|
|
|
aViolationEventInit.mViolatedDirective;
|
|
|
|
|
|
|
|
|
|
// source-file
|
|
|
|
|
if (!aViolationEventInit.mSourceFile.IsEmpty()) {
|
2014-08-04 23:51:10 +04:00
|
|
|
|
report.mCsp_report.mSource_file.Construct();
|
2017-11-29 17:53:00 +03:00
|
|
|
|
report.mCsp_report.mSource_file.Value() = aViolationEventInit.mSourceFile;
|
2014-05-20 18:20:00 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// script-sample
|
2017-11-29 17:53:00 +03:00
|
|
|
|
if (!aViolationEventInit.mSample.IsEmpty()) {
|
2014-08-04 23:51:10 +04:00
|
|
|
|
report.mCsp_report.mScript_sample.Construct();
|
2017-11-29 17:53:00 +03:00
|
|
|
|
report.mCsp_report.mScript_sample.Value() = aViolationEventInit.mSample;
|
2014-05-20 18:20:00 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// line-number
|
2017-11-29 17:53:00 +03:00
|
|
|
|
if (aViolationEventInit.mLineNumber != 0) {
|
2014-08-04 23:51:10 +04:00
|
|
|
|
report.mCsp_report.mLine_number.Construct();
|
2017-11-29 17:53:00 +03:00
|
|
|
|
report.mCsp_report.mLine_number.Value() = aViolationEventInit.mLineNumber;
|
2014-05-20 18:20:00 +04:00
|
|
|
|
}
|
|
|
|
|
|
2018-07-06 11:28:44 +03:00
|
|
|
|
if (aViolationEventInit.mColumnNumber != 0) {
|
2018-07-05 09:21:04 +03:00
|
|
|
|
report.mCsp_report.mColumn_number.Construct();
|
|
|
|
|
report.mCsp_report.mColumn_number.Value() =
|
|
|
|
|
aViolationEventInit.mColumnNumber;
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-04 23:51:10 +04:00
|
|
|
|
nsString csp_report;
|
|
|
|
|
if (!report.ToJSON(csp_report)) {
|
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
}
|
2014-05-20 18:20:00 +04:00
|
|
|
|
|
|
|
|
|
// ---------- Assembled, now send it to all the report URIs ----------- //
|
|
|
|
|
|
|
|
|
|
nsTArray<nsString> reportURIs;
|
|
|
|
|
mPolicies[aViolatedPolicyIndex]->getReportURIs(reportURIs);
|
|
|
|
|
|
2019-01-02 16:05:23 +03:00
|
|
|
|
nsCOMPtr<Document> doc = do_QueryReferent(mLoadingContext);
|
2014-05-20 18:20:00 +04:00
|
|
|
|
nsCOMPtr<nsIURI> reportURI;
|
|
|
|
|
nsCOMPtr<nsIChannel> reportChannel;
|
|
|
|
|
|
2017-11-29 17:53:00 +03:00
|
|
|
|
nsresult rv;
|
2014-05-20 18:20:00 +04:00
|
|
|
|
for (uint32_t r = 0; r < reportURIs.Length(); r++) {
|
2014-07-03 21:36:53 +04:00
|
|
|
|
nsAutoCString reportURICstring = NS_ConvertUTF16toUTF8(reportURIs[r]);
|
2014-05-20 18:20:00 +04:00
|
|
|
|
// try to create a new uri from every report-uri string
|
|
|
|
|
rv = NS_NewURI(getter_AddRefs(reportURI), reportURIs[r]);
|
|
|
|
|
if (NS_FAILED(rv)) {
|
2019-06-11 18:51:51 +03:00
|
|
|
|
AutoTArray<nsString, 1> params = {reportURIs[r]};
|
2014-05-20 18:20:00 +04:00
|
|
|
|
CSPCONTEXTLOG(("Could not create nsIURI for report URI %s",
|
2014-07-03 21:36:53 +04:00
|
|
|
|
reportURICstring.get()));
|
2019-06-11 18:51:51 +03:00
|
|
|
|
logToConsole("triedToSendReport", params, aViolationEventInit.mSourceFile,
|
|
|
|
|
aViolationEventInit.mSample, aViolationEventInit.mLineNumber,
|
2018-07-05 09:21:04 +03:00
|
|
|
|
aViolationEventInit.mColumnNumber,
|
|
|
|
|
nsIScriptError::errorFlag);
|
2014-05-20 18:20:00 +04:00
|
|
|
|
continue; // don't return yet, there may be more URIs
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// try to create a new channel for every report-uri
|
2015-07-27 21:57:56 +03:00
|
|
|
|
if (doc) {
|
2020-07-15 14:20:45 +03:00
|
|
|
|
rv =
|
|
|
|
|
NS_NewChannel(getter_AddRefs(reportChannel), reportURI, doc,
|
|
|
|
|
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
|
|
|
|
|
nsIContentPolicy::TYPE_CSP_REPORT);
|
2014-09-21 20:36:25 +04:00
|
|
|
|
} else {
|
2020-07-15 14:20:45 +03:00
|
|
|
|
rv = NS_NewChannel(
|
|
|
|
|
getter_AddRefs(reportChannel), reportURI, mLoadingPrincipal,
|
|
|
|
|
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
|
|
|
|
|
nsIContentPolicy::TYPE_CSP_REPORT);
|
2014-09-21 20:36:25 +04:00
|
|
|
|
}
|
|
|
|
|
|
2014-05-20 18:20:00 +04:00
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
|
CSPCONTEXTLOG(("Could not create new channel for report URI %s",
|
2014-07-03 21:36:53 +04:00
|
|
|
|
reportURICstring.get()));
|
2014-05-20 18:20:00 +04:00
|
|
|
|
continue; // don't return yet, there may be more URIs
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-21 20:13:54 +04:00
|
|
|
|
// log a warning to console if scheme is not http or https
|
|
|
|
|
bool isHttpScheme =
|
2019-07-30 10:23:18 +03:00
|
|
|
|
reportURI->SchemeIs("http") || reportURI->SchemeIs("https");
|
2014-09-21 20:13:54 +04:00
|
|
|
|
|
|
|
|
|
if (!isHttpScheme) {
|
2019-06-11 18:51:51 +03:00
|
|
|
|
AutoTArray<nsString, 1> params = {reportURIs[r]};
|
|
|
|
|
logToConsole(
|
|
|
|
|
"reportURInotHttpsOrHttp2", params, aViolationEventInit.mSourceFile,
|
|
|
|
|
aViolationEventInit.mSample, aViolationEventInit.mLineNumber,
|
|
|
|
|
aViolationEventInit.mColumnNumber, nsIScriptError::errorFlag);
|
2016-01-28 02:56:39 +03:00
|
|
|
|
continue;
|
2014-09-21 20:13:54 +04:00
|
|
|
|
}
|
|
|
|
|
|
2014-05-20 18:20:00 +04:00
|
|
|
|
// make sure this is an anonymous request (no cookies) so in case the
|
|
|
|
|
// policy URI is injected, it can't be abused for CSRF.
|
|
|
|
|
nsLoadFlags flags;
|
|
|
|
|
rv = reportChannel->GetLoadFlags(&flags);
|
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
flags |= nsIRequest::LOAD_ANONYMOUS;
|
|
|
|
|
rv = reportChannel->SetLoadFlags(flags);
|
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
|
|
// we need to set an nsIChannelEventSink on the channel object
|
|
|
|
|
// so we can tell it to not follow redirects when posting the reports
|
2015-10-18 08:24:48 +03:00
|
|
|
|
RefPtr<CSPReportRedirectSink> reportSink = new CSPReportRedirectSink();
|
2015-07-27 21:57:56 +03:00
|
|
|
|
if (doc && doc->GetDocShell()) {
|
|
|
|
|
nsCOMPtr<nsINetworkInterceptController> interceptController =
|
|
|
|
|
do_QueryInterface(doc->GetDocShell());
|
2015-03-26 20:46:07 +03:00
|
|
|
|
reportSink->SetInterceptController(interceptController);
|
|
|
|
|
}
|
2014-05-20 18:20:00 +04:00
|
|
|
|
reportChannel->SetNotificationCallbacks(reportSink);
|
|
|
|
|
|
2019-05-22 02:14:27 +03:00
|
|
|
|
// apply the loadgroup taken by setRequestContextWithDocument. If there's
|
|
|
|
|
// no loadgroup, AsyncOpen will fail on process-split necko (since the
|
|
|
|
|
// channel cannot query the iBrowserChild).
|
2014-05-20 18:20:00 +04:00
|
|
|
|
rv = reportChannel->SetLoadGroup(mCallingChannelLoadGroup);
|
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
2017-06-14 03:50:11 +03:00
|
|
|
|
// wire in the string input stream to send the report
|
|
|
|
|
nsCOMPtr<nsIStringInputStream> sis(
|
|
|
|
|
do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID));
|
|
|
|
|
NS_ASSERTION(sis,
|
|
|
|
|
"nsIStringInputStream is needed but not available to send CSP "
|
|
|
|
|
"violation reports");
|
|
|
|
|
nsAutoCString utf8CSPReport = NS_ConvertUTF16toUTF8(csp_report);
|
|
|
|
|
rv = sis->SetData(utf8CSPReport.get(), utf8CSPReport.Length());
|
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
2014-05-20 18:20:00 +04:00
|
|
|
|
nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(reportChannel));
|
2016-01-26 14:52:31 +03:00
|
|
|
|
if (!uploadChannel) {
|
|
|
|
|
// It's possible the URI provided can't be uploaded to, in which case
|
|
|
|
|
// we skip this one. We'll already have warned about a non-HTTP URI
|
|
|
|
|
// earlier.
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-01 11:29:29 +03:00
|
|
|
|
rv = uploadChannel->SetUploadStream(sis, "application/csp-report"_ns, -1);
|
2014-05-20 18:20:00 +04:00
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
|
|
// if this is an HTTP channel, set the request method to post
|
|
|
|
|
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(reportChannel));
|
|
|
|
|
if (httpChannel) {
|
2020-07-01 11:29:29 +03:00
|
|
|
|
rv = httpChannel->SetRequestMethod("POST"_ns);
|
2016-12-20 06:49:32 +03:00
|
|
|
|
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
2014-05-20 18:20:00 +04:00
|
|
|
|
}
|
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
|
RefPtr<CSPViolationReportListener> listener =
|
|
|
|
|
new CSPViolationReportListener();
|
2019-02-12 19:08:25 +03:00
|
|
|
|
rv = reportChannel->AsyncOpen(listener);
|
2014-05-20 18:20:00 +04:00
|
|
|
|
|
|
|
|
|
// AsyncOpen should not fail, but could if there's no load group (like if
|
2019-05-22 02:14:27 +03:00
|
|
|
|
// SetRequestContextWith{Document,Principal} is not given a channel). This
|
|
|
|
|
// should fail quietly and not return an error since it's really ok if
|
|
|
|
|
// reports don't go out, but it's good to log the error locally.
|
2014-05-20 18:20:00 +04:00
|
|
|
|
|
|
|
|
|
if (NS_FAILED(rv)) {
|
2019-06-11 18:51:51 +03:00
|
|
|
|
AutoTArray<nsString, 1> params = {reportURIs[r]};
|
2016-12-16 06:16:31 +03:00
|
|
|
|
CSPCONTEXTLOG(("AsyncOpen failed for report URI %s",
|
|
|
|
|
NS_ConvertUTF16toUTF8(params[0]).get()));
|
2019-06-11 18:51:51 +03:00
|
|
|
|
logToConsole("triedToSendReport", params, aViolationEventInit.mSourceFile,
|
|
|
|
|
aViolationEventInit.mSample, aViolationEventInit.mLineNumber,
|
2018-07-05 09:21:04 +03:00
|
|
|
|
aViolationEventInit.mColumnNumber,
|
|
|
|
|
nsIScriptError::errorFlag);
|
2014-07-03 21:36:53 +04:00
|
|
|
|
} else {
|
|
|
|
|
CSPCONTEXTLOG(
|
|
|
|
|
("Sent violation report to URI %s", reportURICstring.get()));
|
2014-05-20 18:20:00 +04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-29 17:53:00 +03:00
|
|
|
|
nsresult nsCSPContext::FireViolationEvent(
|
2018-10-23 09:17:13 +03:00
|
|
|
|
Element* aTriggeringElement, nsICSPEventListener* aCSPEventListener,
|
2017-11-29 17:53:00 +03:00
|
|
|
|
const mozilla::dom::SecurityPolicyViolationEventInit& aViolationEventInit) {
|
2018-10-23 09:17:13 +03:00
|
|
|
|
if (aCSPEventListener) {
|
2018-07-10 19:53:03 +03:00
|
|
|
|
nsAutoString json;
|
|
|
|
|
if (aViolationEventInit.ToJSON(json)) {
|
2018-10-23 09:17:13 +03:00
|
|
|
|
aCSPEventListener->OnCSPViolationEvent(json);
|
2018-07-10 19:53:03 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-10 18:40:21 +03:00
|
|
|
|
// 1. If target is not null, and global is a Window, and target’s
|
|
|
|
|
// shadow-including root is not global’s associated Document, set target to
|
|
|
|
|
// null.
|
|
|
|
|
RefPtr<EventTarget> eventTarget = aTriggeringElement;
|
|
|
|
|
|
2019-01-02 16:05:23 +03:00
|
|
|
|
nsCOMPtr<Document> doc = do_QueryReferent(mLoadingContext);
|
2018-07-10 18:40:21 +03:00
|
|
|
|
if (doc && aTriggeringElement &&
|
|
|
|
|
aTriggeringElement->GetComposedDoc() != doc) {
|
|
|
|
|
eventTarget = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!eventTarget) {
|
|
|
|
|
// If target is a Window, set target to target’s associated Document.
|
|
|
|
|
eventTarget = doc;
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-11 01:14:51 +03:00
|
|
|
|
if (!eventTarget && mInnerWindowID && XRE_IsParentProcess()) {
|
|
|
|
|
if (RefPtr<WindowGlobalParent> parent =
|
|
|
|
|
WindowGlobalParent::GetByInnerWindowId(mInnerWindowID)) {
|
|
|
|
|
nsAutoString json;
|
|
|
|
|
if (aViolationEventInit.ToJSON(json)) {
|
|
|
|
|
Unused << parent->SendDispatchSecurityPolicyViolation(json);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-10 18:40:21 +03:00
|
|
|
|
if (!eventTarget) {
|
2018-07-10 19:53:03 +03:00
|
|
|
|
// If we are here, we are probably dealing with workers. Those are handled
|
|
|
|
|
// via nsICSPEventListener. Nothing to do here.
|
2017-11-29 17:53:00 +03:00
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RefPtr<mozilla::dom::Event> event =
|
|
|
|
|
mozilla::dom::SecurityPolicyViolationEvent::Constructor(
|
2020-07-01 11:29:29 +03:00
|
|
|
|
eventTarget, u"securitypolicyviolation"_ns, aViolationEventInit);
|
2017-11-29 17:53:00 +03:00
|
|
|
|
event->SetTrusted(true);
|
|
|
|
|
|
2018-04-05 20:42:41 +03:00
|
|
|
|
ErrorResult rv;
|
2018-07-10 18:40:21 +03:00
|
|
|
|
eventTarget->DispatchEvent(*event, rv);
|
2018-04-05 20:42:41 +03:00
|
|
|
|
return rv.StealNSResult();
|
2017-11-29 17:53:00 +03:00
|
|
|
|
}
|
|
|
|
|
|
2014-05-20 18:20:00 +04:00
|
|
|
|
/**
|
|
|
|
|
* Dispatched from the main thread to send reports for one CSP violation.
|
|
|
|
|
*/
|
2016-04-26 03:23:21 +03:00
|
|
|
|
class CSPReportSenderRunnable final : public Runnable {
|
2014-05-20 18:20:00 +04:00
|
|
|
|
public:
|
2018-07-10 18:40:21 +03:00
|
|
|
|
CSPReportSenderRunnable(
|
2018-10-23 09:17:13 +03:00
|
|
|
|
Element* aTriggeringElement, nsICSPEventListener* aCSPEventListener,
|
2018-07-18 17:49:18 +03:00
|
|
|
|
nsIURI* aBlockedURI,
|
|
|
|
|
nsCSPContext::BlockedContentSource aBlockedContentSource,
|
2014-05-20 18:20:00 +04:00
|
|
|
|
nsIURI* aOriginalURI, uint32_t aViolatedPolicyIndex, bool aReportOnlyFlag,
|
|
|
|
|
const nsAString& aViolatedDirective, const nsAString& aObserverSubject,
|
|
|
|
|
const nsAString& aSourceFile, const nsAString& aScriptSample,
|
|
|
|
|
uint32_t aLineNum, uint32_t aColumnNum, nsCSPContext* aCSPContext)
|
2017-06-12 22:34:10 +03:00
|
|
|
|
: mozilla::Runnable("CSPReportSenderRunnable"),
|
2018-07-10 18:40:21 +03:00
|
|
|
|
mTriggeringElement(aTriggeringElement),
|
2018-10-23 09:17:13 +03:00
|
|
|
|
mCSPEventListener(aCSPEventListener),
|
2018-07-18 17:49:18 +03:00
|
|
|
|
mBlockedURI(aBlockedURI),
|
2017-06-12 22:34:10 +03:00
|
|
|
|
mBlockedContentSource(aBlockedContentSource),
|
2014-08-12 23:55:08 +04:00
|
|
|
|
mOriginalURI(aOriginalURI),
|
|
|
|
|
mViolatedPolicyIndex(aViolatedPolicyIndex),
|
2014-05-25 19:11:50 +04:00
|
|
|
|
mReportOnlyFlag(aReportOnlyFlag),
|
2014-05-20 18:20:00 +04:00
|
|
|
|
mViolatedDirective(aViolatedDirective),
|
|
|
|
|
mSourceFile(aSourceFile),
|
|
|
|
|
mScriptSample(aScriptSample),
|
|
|
|
|
mLineNum(aLineNum),
|
2018-07-05 09:21:04 +03:00
|
|
|
|
mColumnNum(aColumnNum),
|
2014-05-20 18:20:00 +04:00
|
|
|
|
mCSPContext(aCSPContext) {
|
2014-10-18 03:33:02 +04:00
|
|
|
|
NS_ASSERTION(!aViolatedDirective.IsEmpty(),
|
|
|
|
|
"Can not send reports without a violated directive");
|
2014-05-20 18:20:00 +04:00
|
|
|
|
// the observer subject is an nsISupports: either an nsISupportsCString
|
|
|
|
|
// from the arg passed in directly, or if that's empty, it's the blocked
|
|
|
|
|
// source.
|
2018-07-18 17:49:18 +03:00
|
|
|
|
if (aObserverSubject.IsEmpty() && mBlockedURI) {
|
|
|
|
|
mObserverSubject = aBlockedURI;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nsAutoCString subject;
|
2014-05-20 18:20:00 +04:00
|
|
|
|
if (aObserverSubject.IsEmpty()) {
|
2018-07-18 17:49:18 +03:00
|
|
|
|
BlockedContentSourceToString(aBlockedContentSource, subject);
|
2014-05-20 18:20:00 +04:00
|
|
|
|
} else {
|
2018-07-18 17:49:18 +03:00
|
|
|
|
CopyUTF16toUTF8(aObserverSubject, subject);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nsCOMPtr<nsISupportsCString> supportscstr =
|
|
|
|
|
do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID);
|
|
|
|
|
if (supportscstr) {
|
|
|
|
|
supportscstr->SetData(subject);
|
2014-05-20 18:20:00 +04:00
|
|
|
|
mObserverSubject = do_QueryInterface(supportscstr);
|
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
}
|
2014-05-20 18:20:00 +04:00
|
|
|
|
|
2016-08-08 05:18:10 +03:00
|
|
|
|
NS_IMETHOD Run() override {
|
2014-05-20 18:20:00 +04:00
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
|
|
2018-01-16 23:59:00 +03:00
|
|
|
|
nsresult rv;
|
|
|
|
|
|
2017-11-29 17:53:00 +03:00
|
|
|
|
// 0) prepare violation data
|
|
|
|
|
mozilla::dom::SecurityPolicyViolationEventInit init;
|
2018-07-18 17:49:18 +03:00
|
|
|
|
|
|
|
|
|
nsAutoCString blockedContentSource;
|
|
|
|
|
BlockedContentSourceToString(mBlockedContentSource, blockedContentSource);
|
2018-07-17 12:13:12 +03:00
|
|
|
|
|
2018-01-16 23:59:00 +03:00
|
|
|
|
rv = mCSPContext->GatherSecurityPolicyViolationEventData(
|
2018-07-18 17:49:18 +03:00
|
|
|
|
mBlockedURI, blockedContentSource, mOriginalURI, mViolatedDirective,
|
2018-07-05 09:21:04 +03:00
|
|
|
|
mViolatedPolicyIndex, mSourceFile, mScriptSample, mLineNum, mColumnNum,
|
2017-11-29 17:53:00 +03:00
|
|
|
|
init);
|
2018-01-16 23:59:00 +03:00
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2017-11-29 17:53:00 +03:00
|
|
|
|
|
2014-05-20 18:20:00 +04:00
|
|
|
|
// 1) notify observers
|
|
|
|
|
nsCOMPtr<nsIObserverService> observerService =
|
|
|
|
|
mozilla::services::GetObserverService();
|
2018-07-18 17:49:18 +03:00
|
|
|
|
if (mObserverSubject && observerService) {
|
|
|
|
|
rv = observerService->NotifyObservers(
|
|
|
|
|
mObserverSubject, CSP_VIOLATION_TOPIC, mViolatedDirective.get());
|
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
}
|
2014-05-20 18:20:00 +04:00
|
|
|
|
|
|
|
|
|
// 2) send reports for the policy that was violated
|
2017-11-29 17:53:00 +03:00
|
|
|
|
mCSPContext->SendReports(init, mViolatedPolicyIndex);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
|
2014-05-20 18:20:00 +04:00
|
|
|
|
// 3) log to console (one per policy violation)
|
2018-11-30 13:46:48 +03:00
|
|
|
|
|
2018-07-18 17:49:18 +03:00
|
|
|
|
if (mBlockedURI) {
|
|
|
|
|
mBlockedURI->GetSpec(blockedContentSource);
|
|
|
|
|
if (blockedContentSource.Length() >
|
|
|
|
|
nsCSPContext::ScriptSampleMaxLength()) {
|
2019-07-30 10:23:18 +03:00
|
|
|
|
bool isData = mBlockedURI->SchemeIs("data");
|
2018-07-16 18:58:04 +03:00
|
|
|
|
if (NS_SUCCEEDED(rv) && isData &&
|
2018-07-18 17:49:18 +03:00
|
|
|
|
blockedContentSource.Length() >
|
|
|
|
|
nsCSPContext::ScriptSampleMaxLength()) {
|
|
|
|
|
blockedContentSource.Truncate(nsCSPContext::ScriptSampleMaxLength());
|
|
|
|
|
blockedContentSource.Append(
|
|
|
|
|
NS_ConvertUTF16toUTF8(nsContentUtils::GetLocalizedEllipsis()));
|
2016-09-13 00:30:43 +03:00
|
|
|
|
}
|
2014-05-20 18:20:00 +04:00
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
}
|
2014-05-20 18:20:00 +04:00
|
|
|
|
|
2018-07-18 17:49:18 +03:00
|
|
|
|
if (blockedContentSource.Length() > 0) {
|
|
|
|
|
nsString blockedContentSource16 =
|
|
|
|
|
NS_ConvertUTF8toUTF16(blockedContentSource);
|
2019-06-11 18:51:51 +03:00
|
|
|
|
AutoTArray<nsString, 2> params = {mViolatedDirective,
|
|
|
|
|
blockedContentSource16};
|
2017-07-12 08:13:37 +03:00
|
|
|
|
mCSPContext->logToConsole(
|
|
|
|
|
mReportOnlyFlag ? "CSPROViolationWithURI" : "CSPViolationWithURI",
|
2019-06-11 18:51:51 +03:00
|
|
|
|
params, mSourceFile, mScriptSample, mLineNum, mColumnNum,
|
|
|
|
|
nsIScriptError::errorFlag);
|
2014-05-20 18:20:00 +04:00
|
|
|
|
}
|
2017-11-29 17:53:00 +03:00
|
|
|
|
|
|
|
|
|
// 4) fire violation event
|
2018-10-23 09:17:13 +03:00
|
|
|
|
mCSPContext->FireViolationEvent(mTriggeringElement, mCSPEventListener,
|
|
|
|
|
init);
|
2017-11-29 17:53:00 +03:00
|
|
|
|
|
2014-05-20 18:20:00 +04:00
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
2018-07-10 18:40:21 +03:00
|
|
|
|
RefPtr<Element> mTriggeringElement;
|
2018-10-23 09:17:13 +03:00
|
|
|
|
nsCOMPtr<nsICSPEventListener> mCSPEventListener;
|
2018-07-18 17:49:18 +03:00
|
|
|
|
nsCOMPtr<nsIURI> mBlockedURI;
|
|
|
|
|
nsCSPContext::BlockedContentSource mBlockedContentSource;
|
2014-05-20 18:20:00 +04:00
|
|
|
|
nsCOMPtr<nsIURI> mOriginalURI;
|
|
|
|
|
uint32_t mViolatedPolicyIndex;
|
2014-05-25 19:11:50 +04:00
|
|
|
|
bool mReportOnlyFlag;
|
2014-05-20 18:20:00 +04:00
|
|
|
|
nsString mViolatedDirective;
|
|
|
|
|
nsCOMPtr<nsISupports> mObserverSubject;
|
|
|
|
|
nsString mSourceFile;
|
|
|
|
|
nsString mScriptSample;
|
|
|
|
|
uint32_t mLineNum;
|
2018-07-05 09:21:04 +03:00
|
|
|
|
uint32_t mColumnNum;
|
2015-11-11 17:23:57 +03:00
|
|
|
|
RefPtr<nsCSPContext> mCSPContext;
|
2014-05-20 18:20:00 +04:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Asynchronously notifies any nsIObservers listening to the CSP violation
|
|
|
|
|
* topic that a violation occurred. Also triggers report sending and console
|
|
|
|
|
* logging. All asynchronous on the main thread.
|
|
|
|
|
*
|
2018-07-10 18:40:21 +03:00
|
|
|
|
* @param aTriggeringElement
|
|
|
|
|
* The element that triggered this report violation. It can be null.
|
2014-05-20 18:20:00 +04:00
|
|
|
|
* @param aBlockedContentSource
|
|
|
|
|
* Either a CSP Source (like 'self', as string) or nsIURI: the source
|
|
|
|
|
* of the violation.
|
|
|
|
|
* @param aOriginalUri
|
|
|
|
|
* The original URI if the blocked content is a redirect, else null
|
|
|
|
|
* @param aViolatedDirective
|
|
|
|
|
* the directive that was violated (string).
|
|
|
|
|
* @param aViolatedPolicyIndex
|
|
|
|
|
* the index of the policy that was violated (so we know where to send
|
|
|
|
|
* the reports).
|
|
|
|
|
* @param aObserverSubject
|
|
|
|
|
* optional, subject sent to the nsIObservers listening to the CSP
|
|
|
|
|
* violation topic.
|
|
|
|
|
* @param aSourceFile
|
|
|
|
|
* name of the file containing the inline script violation
|
|
|
|
|
* @param aScriptSample
|
|
|
|
|
* a sample of the violating inline script
|
|
|
|
|
* @param aLineNum
|
|
|
|
|
* source line number of the violation (if available)
|
2018-07-05 09:21:04 +03:00
|
|
|
|
* @param aColumnNum
|
|
|
|
|
* source column number of the violation (if available)
|
2014-05-20 18:20:00 +04:00
|
|
|
|
*/
|
2018-07-10 18:40:21 +03:00
|
|
|
|
nsresult nsCSPContext::AsyncReportViolation(
|
2020-04-11 01:15:21 +03:00
|
|
|
|
Element* aTriggeringElement, nsICSPEventListener* aCSPEventListener,
|
|
|
|
|
nsIURI* aBlockedURI, BlockedContentSource aBlockedContentSource,
|
|
|
|
|
nsIURI* aOriginalURI, const nsAString& aViolatedDirective,
|
|
|
|
|
uint32_t aViolatedPolicyIndex, const nsAString& aObserverSubject,
|
|
|
|
|
const nsAString& aSourceFile, const nsAString& aScriptSample,
|
|
|
|
|
uint32_t aLineNum, uint32_t aColumnNum) {
|
|
|
|
|
EnsureIPCPoliciesRead();
|
|
|
|
|
NS_ENSURE_ARG_MAX(aViolatedPolicyIndex, mPolicies.Length() - 1);
|
2014-05-25 19:11:50 +04:00
|
|
|
|
|
2018-07-10 18:40:21 +03:00
|
|
|
|
nsCOMPtr<nsIRunnable> task = new CSPReportSenderRunnable(
|
|
|
|
|
aTriggeringElement, aCSPEventListener, aBlockedURI, aBlockedContentSource,
|
2017-03-29 05:20:32 +03:00
|
|
|
|
aOriginalURI, aViolatedPolicyIndex,
|
2020-04-11 01:15:21 +03:00
|
|
|
|
mPolicies[aViolatedPolicyIndex]->getReportOnlyFlag(), aViolatedDirective,
|
|
|
|
|
aObserverSubject, aSourceFile, aScriptSample, aLineNum, aColumnNum, this);
|
2017-03-29 05:20:32 +03:00
|
|
|
|
|
|
|
|
|
if (XRE_IsContentProcess()) {
|
2020-04-11 01:15:21 +03:00
|
|
|
|
if (mEventTarget) {
|
|
|
|
|
mEventTarget->Dispatch(task.forget(), NS_DISPATCH_NORMAL);
|
2017-03-29 05:20:32 +03:00
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NS_DispatchToMainThread(task.forget());
|
|
|
|
|
return NS_OK;
|
2014-05-20 18:20:00 +04:00
|
|
|
|
}
|
|
|
|
|
|
2014-05-21 01:59:51 +04:00
|
|
|
|
/**
|
2019-10-22 13:57:43 +03:00
|
|
|
|
* Based on the given loadinfo, determines if this CSP context allows the
|
2014-05-21 01:59:51 +04:00
|
|
|
|
* ancestry.
|
|
|
|
|
*
|
|
|
|
|
* In order to determine the URI of the parent document (one causing the load
|
2019-10-22 13:57:43 +03:00
|
|
|
|
* of this protected document), this function traverses all Browsing Contexts
|
|
|
|
|
* until it reaches the top level browsing context.
|
2014-05-21 01:59:51 +04:00
|
|
|
|
*/
|
2014-04-01 20:35:22 +04:00
|
|
|
|
NS_IMETHODIMP
|
2019-10-22 13:57:43 +03:00
|
|
|
|
nsCSPContext::PermitsAncestry(nsILoadInfo* aLoadInfo,
|
2014-04-01 20:35:22 +04:00
|
|
|
|
bool* outPermitsAncestry) {
|
2019-10-22 13:57:43 +03:00
|
|
|
|
nsresult rv;
|
2014-05-21 01:59:51 +04:00
|
|
|
|
|
2019-10-22 13:25:49 +03:00
|
|
|
|
*outPermitsAncestry = true;
|
2019-10-22 11:53:47 +03:00
|
|
|
|
|
2019-10-22 13:57:43 +03:00
|
|
|
|
RefPtr<mozilla::dom::BrowsingContext> ctx;
|
|
|
|
|
aLoadInfo->GetBrowsingContext(getter_AddRefs(ctx));
|
|
|
|
|
|
2014-05-21 01:59:51 +04:00
|
|
|
|
// extract the ancestry as an array
|
|
|
|
|
nsCOMArray<nsIURI> ancestorsArray;
|
|
|
|
|
nsCOMPtr<nsIURI> uriClone;
|
|
|
|
|
|
2019-10-22 13:57:43 +03:00
|
|
|
|
while (ctx) {
|
2019-11-27 17:26:38 +03:00
|
|
|
|
nsCOMPtr<nsIURI> currentURI;
|
2020-06-26 17:28:43 +03:00
|
|
|
|
// Generally permitsAncestry is consulted from within the
|
|
|
|
|
// DocumentLoadListener in the parent process. For loads of type object
|
|
|
|
|
// and embed it's called from the Document in the content process.
|
|
|
|
|
// After Bug 1646899 we should be able to remove that branching code for
|
|
|
|
|
// querying the currentURI.
|
|
|
|
|
if (XRE_IsParentProcess()) {
|
|
|
|
|
WindowGlobalParent* window = ctx->Canonical()->GetCurrentWindowGlobal();
|
|
|
|
|
if (window) {
|
|
|
|
|
currentURI = window->GetDocumentURI();
|
|
|
|
|
}
|
|
|
|
|
} else if (nsPIDOMWindowOuter* windowOuter = ctx->GetDOMWindow()) {
|
|
|
|
|
currentURI = windowOuter->GetDocumentURI();
|
2019-11-27 17:26:38 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (currentURI) {
|
|
|
|
|
nsAutoCString spec;
|
|
|
|
|
currentURI->GetSpec(spec);
|
|
|
|
|
// delete the userpass from the URI.
|
|
|
|
|
rv = NS_MutateURI(currentURI)
|
|
|
|
|
.SetRef(EmptyCString())
|
|
|
|
|
.SetUserPass(EmptyCString())
|
|
|
|
|
.Finalize(uriClone);
|
|
|
|
|
|
|
|
|
|
// If setUserPass fails for some reason, just return a clone of the
|
|
|
|
|
// current URI
|
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
|
rv = NS_GetURIWithoutRef(currentURI, getter_AddRefs(uriClone));
|
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2014-05-21 01:59:51 +04:00
|
|
|
|
}
|
2019-11-27 17:26:38 +03:00
|
|
|
|
ancestorsArray.AppendElement(uriClone);
|
2014-05-21 01:59:51 +04:00
|
|
|
|
}
|
2019-10-22 13:57:43 +03:00
|
|
|
|
ctx = ctx->GetParent();
|
2014-05-21 01:59:51 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nsAutoString violatedDirective;
|
|
|
|
|
|
|
|
|
|
// Now that we've got the ancestry chain in ancestorsArray, time to check
|
|
|
|
|
// them against any CSP.
|
2014-12-10 15:54:00 +03:00
|
|
|
|
// NOTE: the ancestors are not allowed to be sent cross origin; this is a
|
|
|
|
|
// restriction not placed on subresource loads.
|
2014-06-13 22:06:04 +04:00
|
|
|
|
|
2014-12-10 15:54:00 +03:00
|
|
|
|
for (uint32_t a = 0; a < ancestorsArray.Length(); a++) {
|
2015-05-12 00:22:04 +03:00
|
|
|
|
if (CSPCONTEXTLOGENABLED()) {
|
2016-08-26 09:02:31 +03:00
|
|
|
|
CSPCONTEXTLOG(("nsCSPContext::PermitsAncestry, checking ancestor: %s",
|
|
|
|
|
ancestorsArray[a]->GetSpecOrDefault().get()));
|
2014-12-10 15:54:00 +03:00
|
|
|
|
}
|
|
|
|
|
// omit the ancestor URI in violation reports if cross-origin as per spec
|
|
|
|
|
// (it is a violation of the same-origin policy).
|
|
|
|
|
bool okToSendAncestor =
|
|
|
|
|
NS_SecurityCompareURIs(ancestorsArray[a], mSelfURI, true);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
|
2014-12-10 15:54:00 +03:00
|
|
|
|
bool permits =
|
2020-04-11 01:15:21 +03:00
|
|
|
|
permitsInternal(nsIContentSecurityPolicy::FRAME_ANCESTORS_DIRECTIVE,
|
2018-10-23 09:17:13 +03:00
|
|
|
|
nullptr, // triggering element
|
|
|
|
|
nullptr, // nsICSPEventListener
|
2014-12-10 15:54:00 +03:00
|
|
|
|
ancestorsArray[a],
|
|
|
|
|
nullptr, // no redirect here.
|
|
|
|
|
EmptyString(), // no nonce
|
|
|
|
|
false, // not a preload.
|
|
|
|
|
true, // specific, do not use default-src
|
|
|
|
|
true, // send violation reports
|
2016-11-08 14:55:23 +03:00
|
|
|
|
okToSendAncestor,
|
|
|
|
|
false); // not parser created
|
2014-12-10 15:54:00 +03:00
|
|
|
|
if (!permits) {
|
|
|
|
|
*outPermitsAncestry = false;
|
2014-05-21 01:59:51 +04:00
|
|
|
|
}
|
|
|
|
|
}
|
2014-04-01 20:35:22 +04:00
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-16 03:26:59 +04:00
|
|
|
|
NS_IMETHODIMP
|
2018-07-10 18:40:21 +03:00
|
|
|
|
nsCSPContext::Permits(Element* aTriggeringElement,
|
2018-10-23 09:17:13 +03:00
|
|
|
|
nsICSPEventListener* aCSPEventListener, nsIURI* aURI,
|
2014-12-10 15:54:00 +03:00
|
|
|
|
CSPDirective aDir, bool aSpecific, bool* outPermits) {
|
2014-08-16 03:26:59 +04:00
|
|
|
|
// Can't perform check without aURI
|
|
|
|
|
if (aURI == nullptr) {
|
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-26 15:48:15 +03:00
|
|
|
|
if (aURI->SchemeIs("resource")) {
|
|
|
|
|
// XXX Ideally we would call SubjectToCSP() here but that would also
|
|
|
|
|
// allowlist e.g. javascript: URIs which should not be allowlisted here.
|
|
|
|
|
// As a hotfix we just allowlist pdf.js internals here explicitly.
|
|
|
|
|
nsAutoCString uriSpec;
|
|
|
|
|
aURI->GetSpec(uriSpec);
|
2020-07-01 11:29:29 +03:00
|
|
|
|
if (StringBeginsWith(uriSpec, "resource://pdf.js/"_ns)) {
|
2020-05-26 15:48:15 +03:00
|
|
|
|
*outPermits = true;
|
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-11 01:15:21 +03:00
|
|
|
|
*outPermits =
|
|
|
|
|
permitsInternal(aDir, aTriggeringElement, aCSPEventListener, aURI,
|
|
|
|
|
nullptr, // no original (pre-redirect) URI
|
|
|
|
|
EmptyString(), // no nonce
|
|
|
|
|
false, // not a preload.
|
|
|
|
|
aSpecific,
|
|
|
|
|
true, // send violation reports
|
|
|
|
|
true, // send blocked URI in violation reports
|
|
|
|
|
false); // not parser created
|
2014-11-18 03:12:00 +03:00
|
|
|
|
|
2015-05-12 00:22:04 +03:00
|
|
|
|
if (CSPCONTEXTLOGENABLED()) {
|
|
|
|
|
CSPCONTEXTLOG(("nsCSPContext::Permits, aUri: %s, aDir: %d, isAllowed: %s",
|
2016-08-26 09:02:31 +03:00
|
|
|
|
aURI->GetSpecOrDefault().get(), aDir,
|
|
|
|
|
*outPermits ? "allow" : "deny"));
|
2014-11-18 03:12:00 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-21 21:16:04 +03:00
|
|
|
|
NS_IMETHODIMP
|
|
|
|
|
nsCSPContext::ToJSON(nsAString& outCSPinJSON) {
|
|
|
|
|
outCSPinJSON.Truncate();
|
|
|
|
|
dom::CSPPolicies jsonPolicies;
|
|
|
|
|
jsonPolicies.mCsp_policies.Construct();
|
2019-01-19 03:15:13 +03:00
|
|
|
|
EnsureIPCPoliciesRead();
|
2015-05-21 21:16:04 +03:00
|
|
|
|
|
|
|
|
|
for (uint32_t p = 0; p < mPolicies.Length(); p++) {
|
|
|
|
|
dom::CSP jsonCSP;
|
|
|
|
|
mPolicies[p]->toDomCSPStruct(jsonCSP);
|
2020-04-24 17:34:15 +03:00
|
|
|
|
if (!jsonPolicies.mCsp_policies.Value().AppendElement(jsonCSP, fallible)) {
|
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
|
}
|
2015-05-21 21:16:04 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// convert the gathered information to JSON
|
|
|
|
|
if (!jsonPolicies.ToJSON(outCSPinJSON)) {
|
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-29 17:48:44 +03:00
|
|
|
|
NS_IMETHODIMP
|
|
|
|
|
nsCSPContext::GetCSPSandboxFlags(uint32_t* aOutSandboxFlags) {
|
|
|
|
|
if (!aOutSandboxFlags) {
|
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
*aOutSandboxFlags = SANDBOXED_NONE;
|
|
|
|
|
|
2019-01-19 03:15:13 +03:00
|
|
|
|
EnsureIPCPoliciesRead();
|
2016-06-29 17:48:44 +03:00
|
|
|
|
for (uint32_t i = 0; i < mPolicies.Length(); i++) {
|
|
|
|
|
uint32_t flags = mPolicies[i]->getSandboxFlags();
|
|
|
|
|
|
|
|
|
|
// current policy doesn't have sandbox flag, check next policy
|
|
|
|
|
if (!flags) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// current policy has sandbox flags, if the policy is in enforcement-mode
|
|
|
|
|
// (i.e. not report-only) set these flags and check for policies with more
|
|
|
|
|
// restrictions
|
|
|
|
|
if (!mPolicies[i]->getReportOnlyFlag()) {
|
|
|
|
|
*aOutSandboxFlags |= flags;
|
|
|
|
|
} else {
|
|
|
|
|
// sandbox directive is ignored in report-only mode, warn about it and
|
|
|
|
|
// continue the loop checking for an enforcement policy.
|
|
|
|
|
nsAutoString policy;
|
|
|
|
|
mPolicies[i]->toString(policy);
|
|
|
|
|
|
|
|
|
|
CSPCONTEXTLOG(
|
|
|
|
|
("nsCSPContext::GetCSPSandboxFlags, report only policy, ignoring "
|
|
|
|
|
"sandbox in: %s",
|
2016-12-16 06:16:31 +03:00
|
|
|
|
NS_ConvertUTF16toUTF8(policy).get()));
|
2016-06-29 17:48:44 +03:00
|
|
|
|
|
2019-06-11 18:51:51 +03:00
|
|
|
|
AutoTArray<nsString, 1> params = {policy};
|
|
|
|
|
logToConsole("ignoringReportOnlyDirective", params, EmptyString(),
|
|
|
|
|
EmptyString(), 0, 0, nsIScriptError::warningFlag);
|
2016-06-29 17:48:44 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-20 18:20:00 +04:00
|
|
|
|
/* ========== CSPViolationReportListener implementation ========== */
|
|
|
|
|
|
|
|
|
|
NS_IMPL_ISUPPORTS(CSPViolationReportListener, nsIStreamListener,
|
|
|
|
|
nsIRequestObserver, nsISupports);
|
|
|
|
|
|
2020-03-04 01:07:43 +03:00
|
|
|
|
CSPViolationReportListener::CSPViolationReportListener() = default;
|
2014-05-20 18:20:00 +04:00
|
|
|
|
|
2020-03-04 01:07:43 +03:00
|
|
|
|
CSPViolationReportListener::~CSPViolationReportListener() = default;
|
2014-05-20 18:20:00 +04:00
|
|
|
|
|
|
|
|
|
nsresult AppendSegmentToString(nsIInputStream* aInputStream, void* aClosure,
|
|
|
|
|
const char* aRawSegment, uint32_t aToOffset,
|
|
|
|
|
uint32_t aCount, uint32_t* outWrittenCount) {
|
|
|
|
|
nsCString* decodedData = static_cast<nsCString*>(aClosure);
|
|
|
|
|
decodedData->Append(aRawSegment, aCount);
|
|
|
|
|
*outWrittenCount = aCount;
|
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
|
CSPViolationReportListener::OnDataAvailable(nsIRequest* aRequest,
|
|
|
|
|
nsIInputStream* aInputStream,
|
|
|
|
|
uint64_t aOffset, uint32_t aCount) {
|
|
|
|
|
uint32_t read;
|
|
|
|
|
nsCString decodedData;
|
|
|
|
|
return aInputStream->ReadSegments(AppendSegmentToString, &decodedData, aCount,
|
|
|
|
|
&read);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
|
CSPViolationReportListener::OnStopRequest(nsIRequest* aRequest,
|
|
|
|
|
nsresult aStatus) {
|
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2019-02-28 02:41:04 +03:00
|
|
|
|
CSPViolationReportListener::OnStartRequest(nsIRequest* aRequest) {
|
2014-05-20 18:20:00 +04:00
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ========== CSPReportRedirectSink implementation ========== */
|
|
|
|
|
|
|
|
|
|
NS_IMPL_ISUPPORTS(CSPReportRedirectSink, nsIChannelEventSink,
|
|
|
|
|
nsIInterfaceRequestor);
|
|
|
|
|
|
2020-03-04 01:07:43 +03:00
|
|
|
|
CSPReportRedirectSink::CSPReportRedirectSink() = default;
|
2014-05-20 18:20:00 +04:00
|
|
|
|
|
2020-03-04 01:07:43 +03:00
|
|
|
|
CSPReportRedirectSink::~CSPReportRedirectSink() = default;
|
2014-05-20 18:20:00 +04:00
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
|
CSPReportRedirectSink::AsyncOnChannelRedirect(
|
|
|
|
|
nsIChannel* aOldChannel, nsIChannel* aNewChannel, uint32_t aRedirFlags,
|
|
|
|
|
nsIAsyncVerifyRedirectCallback* aCallback) {
|
2017-10-09 20:03:40 +03:00
|
|
|
|
if (aRedirFlags & nsIChannelEventSink::REDIRECT_INTERNAL) {
|
|
|
|
|
aCallback->OnRedirectVerifyCallback(NS_OK);
|
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-20 18:20:00 +04:00
|
|
|
|
// cancel the old channel so XHR failure callback happens
|
|
|
|
|
nsresult rv = aOldChannel->Cancel(NS_ERROR_ABORT);
|
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
|
|
// notify an observer that we have blocked the report POST due to a redirect,
|
|
|
|
|
// used in testing, do this async since we're in an async call now to begin
|
|
|
|
|
// with
|
|
|
|
|
nsCOMPtr<nsIURI> uri;
|
|
|
|
|
rv = aOldChannel->GetURI(getter_AddRefs(uri));
|
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
|
|
nsCOMPtr<nsIObserverService> observerService =
|
|
|
|
|
mozilla::services::GetObserverService();
|
|
|
|
|
NS_ASSERTION(observerService,
|
|
|
|
|
"Observer service required to log CSP violations");
|
|
|
|
|
observerService->NotifyObservers(
|
|
|
|
|
uri, CSP_VIOLATION_TOPIC,
|
2016-07-21 08:03:25 +03:00
|
|
|
|
u"denied redirect while sending violation report");
|
2014-05-20 18:20:00 +04:00
|
|
|
|
|
|
|
|
|
return NS_BINDING_REDIRECTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
|
CSPReportRedirectSink::GetInterface(const nsIID& aIID, void** aResult) {
|
2015-03-26 20:46:07 +03:00
|
|
|
|
if (aIID.Equals(NS_GET_IID(nsINetworkInterceptController)) &&
|
|
|
|
|
mInterceptController) {
|
|
|
|
|
nsCOMPtr<nsINetworkInterceptController> copy(mInterceptController);
|
|
|
|
|
*aResult = copy.forget().take();
|
|
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-20 18:20:00 +04:00
|
|
|
|
return QueryInterface(aIID, aResult);
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-26 20:46:07 +03:00
|
|
|
|
void CSPReportRedirectSink::SetInterceptController(
|
|
|
|
|
nsINetworkInterceptController* aInterceptController) {
|
|
|
|
|
mInterceptController = aInterceptController;
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-01 20:35:22 +04:00
|
|
|
|
/* ===== nsISerializable implementation ====== */
|
2014-04-02 03:00:19 +04:00
|
|
|
|
|
2014-04-01 20:35:22 +04:00
|
|
|
|
NS_IMETHODIMP
|
|
|
|
|
nsCSPContext::Read(nsIObjectInputStream* aStream) {
|
2014-04-02 03:00:19 +04:00
|
|
|
|
nsresult rv;
|
|
|
|
|
nsCOMPtr<nsISupports> supports;
|
|
|
|
|
|
|
|
|
|
rv = NS_ReadOptionalObject(aStream, true, getter_AddRefs(supports));
|
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
|
|
mSelfURI = do_QueryInterface(supports);
|
2019-05-22 02:14:27 +03:00
|
|
|
|
MOZ_ASSERT(mSelfURI, "need a self URI to de-serialize");
|
|
|
|
|
|
2019-06-03 15:37:12 +03:00
|
|
|
|
nsAutoCString JSON;
|
|
|
|
|
rv = aStream->ReadCString(JSON);
|
2019-05-22 02:14:27 +03:00
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
2019-06-03 15:37:12 +03:00
|
|
|
|
nsCOMPtr<nsIPrincipal> principal = BasePrincipal::FromJSON(JSON);
|
|
|
|
|
mLoadingPrincipal = principal;
|
2019-05-22 02:14:27 +03:00
|
|
|
|
MOZ_ASSERT(mLoadingPrincipal, "need a loadingPrincipal to de-serialize");
|
2014-04-02 03:00:19 +04:00
|
|
|
|
|
|
|
|
|
uint32_t numPolicies;
|
|
|
|
|
rv = aStream->Read32(&numPolicies);
|
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
|
|
nsAutoString policyString;
|
|
|
|
|
|
|
|
|
|
while (numPolicies > 0) {
|
|
|
|
|
numPolicies--;
|
|
|
|
|
|
|
|
|
|
rv = aStream->ReadString(policyString);
|
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
|
|
bool reportOnly = false;
|
|
|
|
|
rv = aStream->ReadBoolean(&reportOnly);
|
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
2018-11-20 02:18:21 +03:00
|
|
|
|
bool deliveredViaMetaTag = false;
|
|
|
|
|
rv = aStream->ReadBoolean(&deliveredViaMetaTag);
|
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2020-04-11 01:14:16 +03:00
|
|
|
|
AddIPCPolicy(mozilla::ipc::ContentSecurityPolicy(policyString, reportOnly,
|
|
|
|
|
deliveredViaMetaTag));
|
2014-04-02 03:00:19 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NS_OK;
|
2014-04-01 20:35:22 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
|
nsCSPContext::Write(nsIObjectOutputStream* aStream) {
|
2014-04-02 03:00:19 +04:00
|
|
|
|
nsresult rv = NS_WriteOptionalCompoundObject(aStream, mSelfURI,
|
|
|
|
|
NS_GET_IID(nsIURI), true);
|
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
2019-06-03 15:37:12 +03:00
|
|
|
|
nsAutoCString JSON;
|
|
|
|
|
BasePrincipal::Cast(mLoadingPrincipal)->ToJSON(JSON);
|
|
|
|
|
rv = aStream->WriteStringZ(JSON.get());
|
2019-05-22 02:14:27 +03:00
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
2014-04-02 03:00:19 +04:00
|
|
|
|
// Serialize all the policies.
|
2019-01-19 03:15:13 +03:00
|
|
|
|
aStream->Write32(mPolicies.Length() + mIPCPolicies.Length());
|
2014-04-02 03:00:19 +04:00
|
|
|
|
|
|
|
|
|
nsAutoString polStr;
|
|
|
|
|
for (uint32_t p = 0; p < mPolicies.Length(); p++) {
|
2014-09-23 21:10:58 +04:00
|
|
|
|
polStr.Truncate();
|
2014-04-02 03:00:19 +04:00
|
|
|
|
mPolicies[p]->toString(polStr);
|
|
|
|
|
aStream->WriteWStringZ(polStr.get());
|
|
|
|
|
aStream->WriteBoolean(mPolicies[p]->getReportOnlyFlag());
|
2018-11-20 02:18:21 +03:00
|
|
|
|
aStream->WriteBoolean(mPolicies[p]->getDeliveredViaMetaTagFlag());
|
2014-04-02 03:00:19 +04:00
|
|
|
|
}
|
2019-01-19 03:15:13 +03:00
|
|
|
|
for (auto& policy : mIPCPolicies) {
|
|
|
|
|
aStream->WriteWStringZ(policy.policy().get());
|
|
|
|
|
aStream->WriteBoolean(policy.reportOnlyFlag());
|
|
|
|
|
aStream->WriteBoolean(policy.deliveredViaMetaTagFlag());
|
|
|
|
|
}
|
2014-04-02 03:00:19 +04:00
|
|
|
|
return NS_OK;
|
2014-04-01 20:35:22 +04:00
|
|
|
|
}
|
2020-04-11 01:14:16 +03:00
|
|
|
|
|
2020-04-11 01:14:38 +03:00
|
|
|
|
void nsCSPContext::AddIPCPolicy(const ContentSecurityPolicy& aPolicy) {
|
2020-04-11 01:14:16 +03:00
|
|
|
|
mIPCPolicies.AppendElement(aPolicy);
|
2020-04-11 01:14:38 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void nsCSPContext::SerializePolicies(
|
|
|
|
|
nsTArray<ContentSecurityPolicy>& aPolicies) {
|
|
|
|
|
for (auto* policy : mPolicies) {
|
|
|
|
|
nsAutoString policyString;
|
|
|
|
|
policy->toString(policyString);
|
|
|
|
|
aPolicies.AppendElement(
|
|
|
|
|
ContentSecurityPolicy(policyString, policy->getReportOnlyFlag(),
|
|
|
|
|
policy->getDeliveredViaMetaTagFlag()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
aPolicies.AppendElements(mIPCPolicies);
|
2020-06-03 02:15:13 +03:00
|
|
|
|
}
|