2017-10-27 00:54:59 +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: */
|
|
|
|
/* 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/. */
|
|
|
|
|
2019-08-01 23:45:31 +03:00
|
|
|
#include "nsArray.h"
|
2015-07-20 05:12:11 +03:00
|
|
|
#include "nsContentSecurityManager.h"
|
2020-07-08 16:11:57 +03:00
|
|
|
#include "nsContentSecurityUtils.h"
|
2020-07-21 20:44:19 +03:00
|
|
|
#include "nsContentPolicyUtils.h"
|
2017-09-12 08:06:38 +03:00
|
|
|
#include "nsEscape.h"
|
2017-11-13 23:25:02 +03:00
|
|
|
#include "nsDataHandler.h"
|
2015-07-20 05:12:11 +03:00
|
|
|
#include "nsIChannel.h"
|
2016-05-17 13:04:11 +03:00
|
|
|
#include "nsIHttpChannelInternal.h"
|
2018-01-30 07:10:53 +03:00
|
|
|
#include "nsINode.h"
|
2015-07-20 05:12:11 +03:00
|
|
|
#include "nsIStreamListener.h"
|
|
|
|
#include "nsILoadInfo.h"
|
2017-09-06 10:33:10 +03:00
|
|
|
#include "nsIOService.h"
|
2015-07-20 05:12:11 +03:00
|
|
|
#include "nsContentUtils.h"
|
|
|
|
#include "nsCORSListenerProxy.h"
|
|
|
|
#include "nsIStreamListener.h"
|
2018-09-28 16:06:29 +03:00
|
|
|
#include "nsIRedirectHistoryEntry.h"
|
2019-08-01 23:45:31 +03:00
|
|
|
#include "nsReadableUtils.h"
|
2020-05-20 16:01:35 +03:00
|
|
|
#include "nsIXPConnect.h"
|
2017-02-03 06:49:07 +03:00
|
|
|
|
2019-01-03 23:55:38 +03:00
|
|
|
#include "mozilla/BasePrincipal.h"
|
2019-04-18 16:54:43 +03:00
|
|
|
#include "mozilla/ClearOnShutdown.h"
|
2020-05-20 16:01:35 +03:00
|
|
|
#include "mozilla/CmdLineAndEnvUtils.h"
|
2015-07-20 05:12:11 +03:00
|
|
|
#include "mozilla/dom/Element.h"
|
2018-03-01 11:44:30 +03:00
|
|
|
#include "mozilla/dom/nsMixedContentBlocker.h"
|
2019-04-10 01:39:01 +03:00
|
|
|
#include "mozilla/dom/BrowserChild.h"
|
2020-07-08 16:11:57 +03:00
|
|
|
#include "mozilla/dom/ContentChild.h"
|
|
|
|
#include "mozilla/dom/ContentParent.h"
|
2018-12-17 04:27:58 +03:00
|
|
|
#include "mozilla/Components.h"
|
2018-09-28 16:06:29 +03:00
|
|
|
#include "mozilla/Logging.h"
|
2020-01-22 14:04:17 +03:00
|
|
|
#include "mozilla/StaticPrefs_dom.h"
|
2020-05-20 16:01:35 +03:00
|
|
|
#include "mozilla/StaticPrefs_security.h"
|
2019-08-01 23:45:31 +03:00
|
|
|
#include "mozilla/Telemetry.h"
|
|
|
|
#include "mozilla/TelemetryComms.h"
|
2019-04-10 17:20:12 +03:00
|
|
|
#include "xpcpublic.h"
|
2018-09-28 16:06:29 +03:00
|
|
|
|
2019-08-01 23:45:31 +03:00
|
|
|
#include "jsapi.h"
|
|
|
|
#include "js/RegExp.h"
|
|
|
|
|
|
|
|
using namespace mozilla::Telemetry;
|
|
|
|
|
2015-12-07 02:33:14 +03:00
|
|
|
NS_IMPL_ISUPPORTS(nsContentSecurityManager, nsIContentSecurityManager,
|
|
|
|
nsIChannelEventSink)
|
2015-09-18 19:27:15 +03:00
|
|
|
|
2018-09-28 16:06:29 +03:00
|
|
|
static mozilla::LazyLogModule sCSMLog("CSMLog");
|
|
|
|
|
2019-08-06 22:56:23 +03:00
|
|
|
static Atomic<bool, mozilla::Relaxed> sTelemetryEventEnabled(false);
|
|
|
|
|
2019-02-26 01:05:29 +03:00
|
|
|
/* static */
|
|
|
|
bool nsContentSecurityManager::AllowTopLevelNavigationToDataURI(
|
2017-11-03 15:23:11 +03:00
|
|
|
nsIChannel* aChannel) {
|
2017-09-06 10:33:10 +03:00
|
|
|
// Let's block all toplevel document navigations to a data: URI.
|
|
|
|
// In all cases where the toplevel document is navigated to a
|
2019-07-08 19:37:45 +03:00
|
|
|
// data: URI the triggeringPrincipal is a contentPrincipal, or
|
2017-09-06 10:33:10 +03:00
|
|
|
// a NullPrincipal. In other cases, e.g. typing a data: URL into
|
|
|
|
// the URL-Bar, the triggeringPrincipal is a SystemPrincipal;
|
|
|
|
// we don't want to block those loads. Only exception, loads coming
|
|
|
|
// from an external applicaton (e.g. Thunderbird) don't load
|
2019-07-08 19:37:45 +03:00
|
|
|
// using a contentPrincipal, but we want to block those loads.
|
2020-05-28 21:23:25 +03:00
|
|
|
if (!StaticPrefs::security_data_uri_block_toplevel_data_uri_navigations()) {
|
2017-09-06 10:33:10 +03:00
|
|
|
return true;
|
|
|
|
}
|
2019-02-20 15:27:25 +03:00
|
|
|
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
|
2017-11-03 15:23:11 +03:00
|
|
|
if (loadInfo->GetExternalContentPolicyType() !=
|
|
|
|
nsIContentPolicy::TYPE_DOCUMENT) {
|
2017-09-06 10:33:10 +03:00
|
|
|
return true;
|
|
|
|
}
|
2017-11-08 22:01:41 +03:00
|
|
|
if (loadInfo->GetForceAllowDataURI()) {
|
|
|
|
// if the loadinfo explicitly allows the data URI navigation, let's allow it
|
|
|
|
// now
|
|
|
|
return true;
|
|
|
|
}
|
2017-11-03 15:23:11 +03:00
|
|
|
nsCOMPtr<nsIURI> uri;
|
|
|
|
nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
|
|
|
|
NS_ENSURE_SUCCESS(rv, true);
|
2019-07-30 10:23:18 +03:00
|
|
|
bool isDataURI = uri->SchemeIs("data");
|
2017-09-06 10:33:10 +03:00
|
|
|
if (!isDataURI) {
|
|
|
|
return true;
|
|
|
|
}
|
2017-11-13 23:25:02 +03:00
|
|
|
|
|
|
|
nsAutoCString spec;
|
|
|
|
rv = uri->GetSpec(spec);
|
|
|
|
NS_ENSURE_SUCCESS(rv, true);
|
|
|
|
nsAutoCString contentType;
|
|
|
|
bool base64;
|
|
|
|
rv = nsDataHandler::ParseURI(spec, contentType, nullptr, base64, nullptr);
|
|
|
|
NS_ENSURE_SUCCESS(rv, true);
|
|
|
|
|
2020-06-03 02:15:13 +03:00
|
|
|
// Allow data: images as long as they are not SVGs
|
2020-07-01 11:29:29 +03:00
|
|
|
if (StringBeginsWith(contentType, "image/"_ns) &&
|
2017-11-13 23:25:02 +03:00
|
|
|
!contentType.EqualsLiteral("image/svg+xml")) {
|
2017-09-06 17:27:05 +03:00
|
|
|
return true;
|
|
|
|
}
|
2020-06-03 02:15:13 +03:00
|
|
|
// Allow all plain text types as well as data: PDFs.
|
2017-11-13 23:25:02 +03:00
|
|
|
if (nsContentUtils::IsPlainTextType(contentType) ||
|
|
|
|
contentType.EqualsLiteral("application/pdf")) {
|
2017-09-14 08:34:41 +03:00
|
|
|
return true;
|
|
|
|
}
|
2017-11-03 15:23:11 +03:00
|
|
|
// Redirecting to a toplevel data: URI is not allowed, hence we make
|
|
|
|
// sure the RedirectChain is empty.
|
|
|
|
if (!loadInfo->GetLoadTriggeredFromExternal() &&
|
2019-12-05 07:44:32 +03:00
|
|
|
loadInfo->TriggeringPrincipal()->IsSystemPrincipal() &&
|
2017-11-03 15:23:11 +03:00
|
|
|
loadInfo->RedirectChain().IsEmpty()) {
|
2017-09-06 10:33:10 +03:00
|
|
|
return true;
|
|
|
|
}
|
2017-09-12 08:06:38 +03:00
|
|
|
nsAutoCString dataSpec;
|
2017-11-03 15:23:11 +03:00
|
|
|
uri->GetSpec(dataSpec);
|
2017-09-12 08:06:38 +03:00
|
|
|
if (dataSpec.Length() > 50) {
|
|
|
|
dataSpec.Truncate(50);
|
|
|
|
dataSpec.AppendLiteral("...");
|
2017-09-06 10:33:10 +03:00
|
|
|
}
|
2018-05-30 22:21:18 +03:00
|
|
|
nsCOMPtr<nsISupports> context = loadInfo->ContextForTopLevelLoad();
|
2019-04-10 01:39:01 +03:00
|
|
|
nsCOMPtr<nsIBrowserChild> browserChild = do_QueryInterface(context);
|
2019-01-02 16:05:23 +03:00
|
|
|
nsCOMPtr<Document> doc;
|
2019-04-10 01:39:01 +03:00
|
|
|
if (browserChild) {
|
|
|
|
doc = static_cast<mozilla::dom::BrowserChild*>(browserChild.get())
|
2019-04-13 04:53:10 +03:00
|
|
|
->GetTopLevelDocument();
|
2017-11-03 15:23:11 +03:00
|
|
|
}
|
2019-06-09 00:26:12 +03:00
|
|
|
AutoTArray<nsString, 1> params;
|
|
|
|
CopyUTF8toUTF16(NS_UnescapeURL(dataSpec), *params.AppendElement());
|
|
|
|
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
|
2020-07-01 11:29:29 +03:00
|
|
|
"DATA_URI_BLOCKED"_ns, doc,
|
2019-06-09 00:26:12 +03:00
|
|
|
nsContentUtils::eSECURITY_PROPERTIES,
|
|
|
|
"BlockTopLevelDataURINavigation", params);
|
2017-09-06 10:33:10 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-02-26 01:05:29 +03:00
|
|
|
/* static */
|
|
|
|
bool nsContentSecurityManager::AllowInsecureRedirectToDataURI(
|
2018-02-18 21:52:52 +03:00
|
|
|
nsIChannel* aNewChannel) {
|
2019-02-20 15:27:25 +03:00
|
|
|
nsCOMPtr<nsILoadInfo> loadInfo = aNewChannel->LoadInfo();
|
2018-02-18 21:52:52 +03:00
|
|
|
if (loadInfo->GetExternalContentPolicyType() !=
|
|
|
|
nsIContentPolicy::TYPE_SCRIPT) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
nsCOMPtr<nsIURI> newURI;
|
|
|
|
nsresult rv = NS_GetFinalChannelURI(aNewChannel, getter_AddRefs(newURI));
|
|
|
|
if (NS_FAILED(rv) || !newURI) {
|
|
|
|
return true;
|
|
|
|
}
|
2019-07-30 10:23:18 +03:00
|
|
|
bool isDataURI = newURI->SchemeIs("data");
|
2018-02-18 21:52:52 +03:00
|
|
|
if (!isDataURI) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Web Extensions are exempt from that restriction and are allowed to redirect
|
|
|
|
// a channel to a data: URI. When a web extension redirects a channel, we set
|
|
|
|
// a flag on the loadInfo which allows us to identify such redirects here.
|
|
|
|
if (loadInfo->GetAllowInsecureRedirectToDataURI()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsAutoCString dataSpec;
|
|
|
|
newURI->GetSpec(dataSpec);
|
|
|
|
if (dataSpec.Length() > 50) {
|
|
|
|
dataSpec.Truncate(50);
|
|
|
|
dataSpec.AppendLiteral("...");
|
|
|
|
}
|
2019-01-02 16:05:23 +03:00
|
|
|
nsCOMPtr<Document> doc;
|
2018-02-18 21:52:52 +03:00
|
|
|
nsINode* node = loadInfo->LoadingNode();
|
|
|
|
if (node) {
|
|
|
|
doc = node->OwnerDoc();
|
|
|
|
}
|
2019-06-09 00:26:12 +03:00
|
|
|
AutoTArray<nsString, 1> params;
|
|
|
|
CopyUTF8toUTF16(NS_UnescapeURL(dataSpec), *params.AppendElement());
|
|
|
|
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
|
2020-07-01 11:29:29 +03:00
|
|
|
"DATA_URI_BLOCKED"_ns, doc,
|
2019-06-09 00:26:12 +03:00
|
|
|
nsContentUtils::eSECURITY_PROPERTIES,
|
|
|
|
"BlockSubresourceRedirectToData", params);
|
2018-02-18 21:52:52 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-02-26 01:05:29 +03:00
|
|
|
/* static */
|
|
|
|
nsresult nsContentSecurityManager::CheckFTPSubresourceLoad(
|
2018-04-06 01:27:02 +03:00
|
|
|
nsIChannel* aChannel) {
|
2019-08-11 23:46:06 +03:00
|
|
|
// We dissallow using FTP resources as a subresource everywhere.
|
2018-03-26 22:05:08 +03:00
|
|
|
// The only valid way to use FTP resources is loading it as
|
|
|
|
// a top level document.
|
|
|
|
|
2019-02-20 15:27:25 +03:00
|
|
|
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
|
2018-03-26 22:05:08 +03:00
|
|
|
nsContentPolicyType type = loadInfo->GetExternalContentPolicyType();
|
2018-06-22 00:31:13 +03:00
|
|
|
|
|
|
|
// Allow top-level FTP documents and save-as download of FTP files on
|
|
|
|
// HTTP pages.
|
|
|
|
if (type == nsIContentPolicy::TYPE_DOCUMENT ||
|
|
|
|
type == nsIContentPolicy::TYPE_SAVEAS_DOWNLOAD) {
|
2018-04-06 01:27:02 +03:00
|
|
|
return NS_OK;
|
2018-03-26 22:05:08 +03:00
|
|
|
}
|
|
|
|
|
2018-06-19 14:58:41 +03:00
|
|
|
// Allow the system principal to load everything. This is meant to
|
|
|
|
// temporarily fix downloads and pdf.js.
|
|
|
|
nsIPrincipal* triggeringPrincipal = loadInfo->TriggeringPrincipal();
|
2019-12-05 07:44:32 +03:00
|
|
|
if (triggeringPrincipal->IsSystemPrincipal()) {
|
2018-06-19 14:58:41 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2018-03-26 22:05:08 +03:00
|
|
|
nsCOMPtr<nsIURI> uri;
|
|
|
|
nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
|
2018-04-06 01:27:02 +03:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
if (!uri) {
|
|
|
|
return NS_OK;
|
2018-03-26 22:05:08 +03:00
|
|
|
}
|
|
|
|
|
2019-07-30 10:23:18 +03:00
|
|
|
bool isFtpURI = uri->SchemeIs("ftp");
|
2018-03-26 22:05:08 +03:00
|
|
|
if (!isFtpURI) {
|
2018-04-06 01:27:02 +03:00
|
|
|
return NS_OK;
|
2018-03-26 22:05:08 +03:00
|
|
|
}
|
|
|
|
|
2019-01-02 16:05:23 +03:00
|
|
|
nsCOMPtr<Document> doc;
|
2018-03-26 22:05:08 +03:00
|
|
|
if (nsINode* node = loadInfo->LoadingNode()) {
|
|
|
|
doc = node->OwnerDoc();
|
|
|
|
}
|
|
|
|
|
|
|
|
nsAutoCString spec;
|
|
|
|
uri->GetSpec(spec);
|
2019-06-09 00:26:12 +03:00
|
|
|
AutoTArray<nsString, 1> params;
|
|
|
|
CopyUTF8toUTF16(NS_UnescapeURL(spec), *params.AppendElement());
|
2018-03-26 22:05:08 +03:00
|
|
|
|
|
|
|
nsContentUtils::ReportToConsole(
|
2020-07-01 11:29:29 +03:00
|
|
|
nsIScriptError::warningFlag, "FTP_URI_BLOCKED"_ns, doc,
|
2019-06-09 00:26:12 +03:00
|
|
|
nsContentUtils::eSECURITY_PROPERTIES, "BlockSubresourceFTP", params);
|
2018-03-26 22:05:08 +03:00
|
|
|
|
2018-04-06 01:27:02 +03:00
|
|
|
return NS_ERROR_CONTENT_BLOCKED;
|
2018-03-26 22:05:08 +03:00
|
|
|
}
|
|
|
|
|
2015-07-20 05:12:11 +03:00
|
|
|
static nsresult ValidateSecurityFlags(nsILoadInfo* aLoadInfo) {
|
|
|
|
nsSecurityFlags securityMode = aLoadInfo->GetSecurityMode();
|
|
|
|
|
2018-03-29 13:16:23 +03:00
|
|
|
// We should never perform a security check on a loadInfo that uses the flag
|
|
|
|
// SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK, because that is only used for
|
|
|
|
// temporary loadInfos used for explicit nsIContentPolicy checks, but never be
|
|
|
|
// set as a security flag on an actual channel.
|
2020-07-15 14:20:45 +03:00
|
|
|
if (securityMode !=
|
|
|
|
nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_INHERITS_SEC_CONTEXT &&
|
2015-07-20 05:12:11 +03:00
|
|
|
securityMode != nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED &&
|
2020-07-15 14:20:45 +03:00
|
|
|
securityMode !=
|
|
|
|
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT &&
|
|
|
|
securityMode != nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL &&
|
|
|
|
securityMode != nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT) {
|
2015-07-20 05:12:11 +03:00
|
|
|
MOZ_ASSERT(
|
|
|
|
false,
|
|
|
|
"need one securityflag from nsILoadInfo to perform security checks");
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// all good, found the right security flags
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2016-04-27 20:41:13 +03:00
|
|
|
static bool IsImageLoadInEditorAppType(nsILoadInfo* aLoadInfo) {
|
|
|
|
// Editor apps get special treatment here, editors can load images
|
|
|
|
// from anywhere. This allows editor to insert images from file://
|
|
|
|
// into documents that are being edited.
|
|
|
|
nsContentPolicyType type = aLoadInfo->InternalContentPolicyType();
|
|
|
|
if (type != nsIContentPolicy::TYPE_INTERNAL_IMAGE &&
|
|
|
|
type != nsIContentPolicy::TYPE_INTERNAL_IMAGE_PRELOAD &&
|
2016-10-13 10:43:54 +03:00
|
|
|
type != nsIContentPolicy::TYPE_INTERNAL_IMAGE_FAVICON &&
|
2016-04-27 20:41:13 +03:00
|
|
|
type != nsIContentPolicy::TYPE_IMAGESET) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-11-28 06:30:56 +03:00
|
|
|
auto appType = nsIDocShell::APP_TYPE_UNKNOWN;
|
2016-04-27 20:41:13 +03:00
|
|
|
nsINode* node = aLoadInfo->LoadingNode();
|
|
|
|
if (!node) {
|
|
|
|
return false;
|
|
|
|
}
|
2019-01-02 16:05:23 +03:00
|
|
|
Document* doc = node->OwnerDoc();
|
2016-04-27 20:41:13 +03:00
|
|
|
if (!doc) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem = doc->GetDocShell();
|
|
|
|
if (!docShellTreeItem) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDocShellTreeItem> root;
|
2019-08-07 22:24:00 +03:00
|
|
|
docShellTreeItem->GetInProcessRootTreeItem(getter_AddRefs(root));
|
2016-04-27 20:41:13 +03:00
|
|
|
nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(root));
|
2018-11-28 06:30:56 +03:00
|
|
|
if (docShell) {
|
|
|
|
appType = docShell->GetAppType();
|
2016-04-27 20:41:13 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return appType == nsIDocShell::APP_TYPE_EDITOR;
|
|
|
|
}
|
|
|
|
|
2015-07-20 05:12:11 +03:00
|
|
|
static nsresult DoCheckLoadURIChecks(nsIURI* aURI, nsILoadInfo* aLoadInfo) {
|
2019-07-08 13:47:05 +03:00
|
|
|
// In practice, these DTDs are just used for localization, so applying the
|
|
|
|
// same principal check as Fluent.
|
|
|
|
if (aLoadInfo->InternalContentPolicyType() ==
|
|
|
|
nsIContentPolicy::TYPE_INTERNAL_DTD) {
|
2019-09-25 13:39:45 +03:00
|
|
|
RefPtr<Document> doc;
|
|
|
|
aLoadInfo->GetLoadingDocument(getter_AddRefs(doc));
|
2020-03-26 16:18:40 +03:00
|
|
|
bool allowed = false;
|
|
|
|
aLoadInfo->TriggeringPrincipal()->IsL10nAllowed(
|
|
|
|
doc ? doc->GetDocumentURI() : nullptr, &allowed);
|
|
|
|
|
|
|
|
return allowed ? NS_OK : NS_ERROR_DOM_BAD_URI;
|
2019-07-08 13:47:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// This is used in order to allow a privileged DOMParser to parse documents
|
|
|
|
// that need to access localization DTDs. We just allow through
|
|
|
|
// TYPE_INTERNAL_FORCE_ALLOWED_DTD no matter what the triggering principal is.
|
|
|
|
if (aLoadInfo->InternalContentPolicyType() ==
|
|
|
|
nsIContentPolicy::TYPE_INTERNAL_FORCE_ALLOWED_DTD) {
|
2015-11-26 00:38:05 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2016-05-29 21:40:16 +03:00
|
|
|
if (IsImageLoadInEditorAppType(aLoadInfo)) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2015-07-20 05:12:11 +03:00
|
|
|
|
2016-05-29 21:40:16 +03:00
|
|
|
// Only call CheckLoadURIWithPrincipal() using the TriggeringPrincipal and not
|
|
|
|
// the LoadingPrincipal when SEC_ALLOW_CROSS_ORIGIN_* security flags are set,
|
|
|
|
// to allow, e.g. user stylesheets to load chrome:// URIs.
|
|
|
|
return nsContentUtils::GetSecurityManager()->CheckLoadURIWithPrincipal(
|
2019-12-12 19:41:19 +03:00
|
|
|
aLoadInfo->TriggeringPrincipal(), aURI, aLoadInfo->CheckLoadURIFlags(),
|
|
|
|
aLoadInfo->GetInnerWindowID());
|
2015-07-20 05:12:11 +03:00
|
|
|
}
|
|
|
|
|
2015-11-04 11:05:16 +03:00
|
|
|
static bool URIHasFlags(nsIURI* aURI, uint32_t aURIFlags) {
|
|
|
|
bool hasFlags;
|
|
|
|
nsresult rv = NS_URIChainHasFlags(aURI, aURIFlags, &hasFlags);
|
|
|
|
NS_ENSURE_SUCCESS(rv, false);
|
|
|
|
|
|
|
|
return hasFlags;
|
|
|
|
}
|
|
|
|
|
2015-12-07 02:33:15 +03:00
|
|
|
static nsresult DoSOPChecks(nsIURI* aURI, nsILoadInfo* aLoadInfo,
|
|
|
|
nsIChannel* aChannel) {
|
2015-11-04 11:05:16 +03:00
|
|
|
if (aLoadInfo->GetAllowChrome() &&
|
|
|
|
(URIHasFlags(aURI, nsIProtocolHandler::URI_IS_UI_RESOURCE) ||
|
2017-09-26 03:21:01 +03:00
|
|
|
nsContentUtils::SchemeIs(aURI, "moz-safe-about"))) {
|
2015-11-04 11:05:16 +03:00
|
|
|
// UI resources are allowed.
|
2015-09-15 04:59:35 +03:00
|
|
|
return DoCheckLoadURIChecks(aURI, aLoadInfo);
|
2015-07-20 05:12:11 +03:00
|
|
|
}
|
|
|
|
|
2019-12-16 12:36:45 +03:00
|
|
|
if (NS_HasBeenCrossOrigin(aChannel, true)) {
|
|
|
|
NS_SetRequestBlockingReason(aLoadInfo,
|
|
|
|
nsILoadInfo::BLOCKING_REASON_NOT_SAME_ORIGIN);
|
|
|
|
return NS_ERROR_DOM_BAD_URI;
|
|
|
|
}
|
2015-12-05 18:34:47 +03:00
|
|
|
|
2015-12-07 02:33:15 +03:00
|
|
|
return NS_OK;
|
2015-09-15 04:59:35 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static nsresult DoCORSChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo,
|
|
|
|
nsCOMPtr<nsIStreamListener>& aInAndOutListener) {
|
2015-10-27 00:22:59 +03:00
|
|
|
MOZ_RELEASE_ASSERT(aInAndOutListener,
|
|
|
|
"can not perform CORS checks without a listener");
|
2016-03-19 02:14:03 +03:00
|
|
|
|
|
|
|
// No need to set up CORS if TriggeringPrincipal is the SystemPrincipal.
|
2019-12-05 07:44:32 +03:00
|
|
|
if (aLoadInfo->TriggeringPrincipal()->IsSystemPrincipal()) {
|
2016-03-19 02:14:03 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2018-10-31 21:02:46 +03:00
|
|
|
// We use the triggering principal here, rather than the loading principal
|
|
|
|
// to ensure that anonymous CORS content in the browser resources and in
|
|
|
|
// WebExtensions is allowed to load.
|
|
|
|
nsIPrincipal* principal = aLoadInfo->TriggeringPrincipal();
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<nsCORSListenerProxy> corsListener = new nsCORSListenerProxy(
|
2015-07-20 05:12:11 +03:00
|
|
|
aInAndOutListener, principal,
|
2015-12-07 02:33:15 +03:00
|
|
|
aLoadInfo->GetCookiePolicy() == nsILoadInfo::SEC_COOKIES_INCLUDE);
|
2015-07-20 05:12:11 +03:00
|
|
|
// XXX: @arg: DataURIHandling::Allow
|
|
|
|
// lets use DataURIHandling::Allow for now and then decide on callsite basis.
|
|
|
|
// see also:
|
|
|
|
// http://mxr.mozilla.org/mozilla-central/source/dom/security/nsCORSListenerProxy.h#33
|
|
|
|
nsresult rv = corsListener->Init(aChannel, DataURIHandling::Allow);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
aInAndOutListener = corsListener;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2016-05-17 13:04:11 +03:00
|
|
|
static nsresult DoContentSecurityChecks(nsIChannel* aChannel,
|
|
|
|
nsILoadInfo* aLoadInfo) {
|
2015-10-19 21:14:54 +03:00
|
|
|
nsContentPolicyType contentPolicyType =
|
|
|
|
aLoadInfo->GetExternalContentPolicyType();
|
2015-10-16 00:07:06 +03:00
|
|
|
nsContentPolicyType internalContentPolicyType =
|
|
|
|
aLoadInfo->InternalContentPolicyType();
|
2015-10-19 21:14:54 +03:00
|
|
|
nsCString mimeTypeGuess;
|
2015-07-20 05:12:11 +03:00
|
|
|
|
2017-01-03 22:59:30 +03:00
|
|
|
nsCOMPtr<nsIURI> uri;
|
|
|
|
nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2015-07-20 05:12:11 +03:00
|
|
|
switch (contentPolicyType) {
|
2015-07-31 18:58:14 +03:00
|
|
|
case nsIContentPolicy::TYPE_OTHER: {
|
|
|
|
mimeTypeGuess = EmptyCString();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-10-19 05:59:18 +03:00
|
|
|
case nsIContentPolicy::TYPE_SCRIPT: {
|
2020-07-01 11:29:29 +03:00
|
|
|
mimeTypeGuess = "application/javascript"_ns;
|
2015-10-19 05:59:18 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2016-02-03 07:35:02 +03:00
|
|
|
case nsIContentPolicy::TYPE_IMAGE: {
|
2016-04-27 20:41:13 +03:00
|
|
|
mimeTypeGuess = EmptyCString();
|
2016-02-03 07:35:02 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case nsIContentPolicy::TYPE_STYLESHEET: {
|
2020-07-01 11:29:29 +03:00
|
|
|
mimeTypeGuess = "text/css"_ns;
|
2016-02-03 07:35:02 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2016-06-28 10:37:55 +03:00
|
|
|
case nsIContentPolicy::TYPE_OBJECT: {
|
|
|
|
mimeTypeGuess = EmptyCString();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-08-10 20:25:20 +03:00
|
|
|
case nsIContentPolicy::TYPE_DOCUMENT: {
|
2017-01-03 22:59:30 +03:00
|
|
|
mimeTypeGuess = EmptyCString();
|
2015-08-10 20:25:20 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case nsIContentPolicy::TYPE_SUBDOCUMENT: {
|
2020-07-01 11:29:29 +03:00
|
|
|
mimeTypeGuess = "text/html"_ns;
|
2015-08-10 20:25:20 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-09-15 04:59:35 +03:00
|
|
|
case nsIContentPolicy::TYPE_REFRESH: {
|
2015-08-05 06:05:37 +03:00
|
|
|
MOZ_ASSERT(false, "contentPolicyType not supported yet");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-08-13 18:53:28 +03:00
|
|
|
case nsIContentPolicy::TYPE_PING: {
|
|
|
|
mimeTypeGuess = EmptyCString();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-08-05 06:06:19 +03:00
|
|
|
case nsIContentPolicy::TYPE_XMLHTTPREQUEST: {
|
|
|
|
// alias nsIContentPolicy::TYPE_DATAREQUEST:
|
2017-09-05 19:01:07 +03:00
|
|
|
#ifdef DEBUG
|
|
|
|
{
|
2018-03-29 13:16:23 +03:00
|
|
|
nsCOMPtr<nsINode> node = aLoadInfo->LoadingNode();
|
2018-01-30 07:10:53 +03:00
|
|
|
MOZ_ASSERT(!node || node->NodeType() == nsINode::DOCUMENT_NODE,
|
2017-09-05 19:01:07 +03:00
|
|
|
"type_xml requires requestingContext of type Document");
|
|
|
|
}
|
|
|
|
#endif
|
2015-10-19 21:14:54 +03:00
|
|
|
// We're checking for the external TYPE_XMLHTTPREQUEST here in case
|
|
|
|
// an addon creates a request with that type.
|
2015-08-10 20:19:08 +03:00
|
|
|
if (internalContentPolicyType ==
|
2015-10-19 21:14:54 +03:00
|
|
|
nsIContentPolicy::TYPE_INTERNAL_XMLHTTPREQUEST ||
|
|
|
|
internalContentPolicyType == nsIContentPolicy::TYPE_XMLHTTPREQUEST) {
|
|
|
|
mimeTypeGuess = EmptyCString();
|
2015-08-10 20:19:08 +03:00
|
|
|
} else {
|
|
|
|
MOZ_ASSERT(internalContentPolicyType ==
|
|
|
|
nsIContentPolicy::TYPE_INTERNAL_EVENTSOURCE,
|
|
|
|
"can not set mime type guess for unexpected internal type");
|
2020-07-01 11:29:29 +03:00
|
|
|
mimeTypeGuess = nsLiteralCString(TEXT_EVENT_STREAM);
|
2015-08-10 20:19:08 +03:00
|
|
|
}
|
2015-08-05 06:06:19 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-08-05 06:05:37 +03:00
|
|
|
case nsIContentPolicy::TYPE_OBJECT_SUBREQUEST: {
|
|
|
|
mimeTypeGuess = EmptyCString();
|
2017-09-05 19:01:07 +03:00
|
|
|
#ifdef DEBUG
|
|
|
|
{
|
2018-03-29 13:16:23 +03:00
|
|
|
nsCOMPtr<nsINode> node = aLoadInfo->LoadingNode();
|
2018-01-30 07:10:53 +03:00
|
|
|
MOZ_ASSERT(
|
|
|
|
!node || node->NodeType() == nsINode::ELEMENT_NODE,
|
2017-09-05 19:01:07 +03:00
|
|
|
"type_subrequest requires requestingContext of type Element");
|
|
|
|
}
|
|
|
|
#endif
|
2015-08-05 06:05:37 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-11-20 21:55:54 +03:00
|
|
|
case nsIContentPolicy::TYPE_DTD: {
|
|
|
|
mimeTypeGuess = EmptyCString();
|
2017-09-05 19:01:07 +03:00
|
|
|
#ifdef DEBUG
|
|
|
|
{
|
2018-03-29 13:16:23 +03:00
|
|
|
nsCOMPtr<nsINode> node = aLoadInfo->LoadingNode();
|
2018-01-30 07:10:53 +03:00
|
|
|
MOZ_ASSERT(!node || node->NodeType() == nsINode::DOCUMENT_NODE,
|
2017-09-05 19:01:07 +03:00
|
|
|
"type_dtd requires requestingContext of type Document");
|
|
|
|
}
|
|
|
|
#endif
|
2015-11-20 21:55:54 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-07-25 20:29:22 +03:00
|
|
|
case nsIContentPolicy::TYPE_FONT: {
|
2016-03-02 00:06:13 +03:00
|
|
|
mimeTypeGuess = EmptyCString();
|
2015-07-20 05:12:11 +03:00
|
|
|
break;
|
2015-07-25 20:29:22 +03:00
|
|
|
}
|
2015-07-20 05:12:11 +03:00
|
|
|
|
2015-07-25 20:29:22 +03:00
|
|
|
case nsIContentPolicy::TYPE_MEDIA: {
|
|
|
|
if (internalContentPolicyType == nsIContentPolicy::TYPE_INTERNAL_TRACK) {
|
2020-07-01 11:29:29 +03:00
|
|
|
mimeTypeGuess = "text/vtt"_ns;
|
2015-07-25 20:29:22 +03:00
|
|
|
} else {
|
|
|
|
mimeTypeGuess = EmptyCString();
|
|
|
|
}
|
2017-09-05 19:01:07 +03:00
|
|
|
#ifdef DEBUG
|
|
|
|
{
|
2018-03-29 13:16:23 +03:00
|
|
|
nsCOMPtr<nsINode> node = aLoadInfo->LoadingNode();
|
2018-01-30 07:10:53 +03:00
|
|
|
MOZ_ASSERT(!node || node->NodeType() == nsINode::ELEMENT_NODE,
|
2017-09-05 19:01:07 +03:00
|
|
|
"type_media requires requestingContext of type Element");
|
|
|
|
}
|
|
|
|
#endif
|
2015-07-20 05:12:11 +03:00
|
|
|
break;
|
2015-07-25 20:29:22 +03:00
|
|
|
}
|
2015-07-20 05:12:11 +03:00
|
|
|
|
2015-07-27 21:57:56 +03:00
|
|
|
case nsIContentPolicy::TYPE_WEBSOCKET: {
|
2016-05-17 13:04:11 +03:00
|
|
|
// Websockets have to use the proxied URI:
|
|
|
|
// ws:// instead of http:// for CSP checks
|
|
|
|
nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal =
|
|
|
|
do_QueryInterface(aChannel);
|
|
|
|
MOZ_ASSERT(httpChannelInternal);
|
|
|
|
if (httpChannelInternal) {
|
2016-12-20 06:49:32 +03:00
|
|
|
rv = httpChannelInternal->GetProxyURI(getter_AddRefs(uri));
|
|
|
|
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
2016-05-17 13:04:11 +03:00
|
|
|
}
|
|
|
|
mimeTypeGuess = EmptyCString();
|
2015-07-28 06:39:17 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-07-27 21:57:56 +03:00
|
|
|
case nsIContentPolicy::TYPE_CSP_REPORT: {
|
|
|
|
mimeTypeGuess = EmptyCString();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-09-29 02:34:47 +03:00
|
|
|
case nsIContentPolicy::TYPE_XSLT: {
|
2020-07-01 11:29:29 +03:00
|
|
|
mimeTypeGuess = "application/xml"_ns;
|
2017-09-05 19:01:07 +03:00
|
|
|
#ifdef DEBUG
|
|
|
|
{
|
2018-03-29 13:16:23 +03:00
|
|
|
nsCOMPtr<nsINode> node = aLoadInfo->LoadingNode();
|
2018-01-30 07:10:53 +03:00
|
|
|
MOZ_ASSERT(!node || node->NodeType() == nsINode::DOCUMENT_NODE,
|
2017-09-05 19:01:07 +03:00
|
|
|
"type_xslt requires requestingContext of type Document");
|
|
|
|
}
|
|
|
|
#endif
|
2015-09-29 02:34:47 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-07-28 06:39:17 +03:00
|
|
|
case nsIContentPolicy::TYPE_BEACON: {
|
|
|
|
mimeTypeGuess = EmptyCString();
|
2017-09-05 19:01:07 +03:00
|
|
|
#ifdef DEBUG
|
|
|
|
{
|
2018-03-29 13:16:23 +03:00
|
|
|
nsCOMPtr<nsINode> node = aLoadInfo->LoadingNode();
|
2018-01-30 07:10:53 +03:00
|
|
|
MOZ_ASSERT(!node || node->NodeType() == nsINode::DOCUMENT_NODE,
|
2017-09-05 19:01:07 +03:00
|
|
|
"type_beacon requires requestingContext of type Document");
|
|
|
|
}
|
|
|
|
#endif
|
2015-07-28 06:39:17 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-10-20 04:24:36 +03:00
|
|
|
case nsIContentPolicy::TYPE_FETCH: {
|
|
|
|
mimeTypeGuess = EmptyCString();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-07-25 20:29:22 +03:00
|
|
|
case nsIContentPolicy::TYPE_IMAGESET: {
|
2016-04-27 20:41:13 +03:00
|
|
|
mimeTypeGuess = EmptyCString();
|
2015-07-20 05:12:11 +03:00
|
|
|
break;
|
2015-07-25 20:29:22 +03:00
|
|
|
}
|
2015-07-20 05:12:11 +03:00
|
|
|
|
2016-04-08 00:13:09 +03:00
|
|
|
case nsIContentPolicy::TYPE_WEB_MANIFEST: {
|
2020-07-01 11:29:29 +03:00
|
|
|
mimeTypeGuess = "application/manifest+json"_ns;
|
2016-04-08 00:13:09 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2017-11-16 14:27:01 +03:00
|
|
|
case nsIContentPolicy::TYPE_SAVEAS_DOWNLOAD: {
|
|
|
|
mimeTypeGuess = EmptyCString();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2018-03-24 01:27:08 +03:00
|
|
|
case nsIContentPolicy::TYPE_SPECULATIVE: {
|
|
|
|
mimeTypeGuess = EmptyCString();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-07-20 05:12:11 +03:00
|
|
|
default:
|
|
|
|
// nsIContentPolicy::TYPE_INVALID
|
|
|
|
MOZ_ASSERT(false,
|
|
|
|
"can not perform security check without a valid contentType");
|
|
|
|
}
|
|
|
|
|
|
|
|
int16_t shouldLoad = nsIContentPolicy::ACCEPT;
|
2018-03-29 13:16:23 +03:00
|
|
|
rv = NS_CheckContentLoadPolicy(uri, aLoadInfo, mimeTypeGuess, &shouldLoad,
|
2017-07-11 01:00:03 +03:00
|
|
|
nsContentUtils::GetContentPolicy());
|
2017-01-03 22:59:30 +03:00
|
|
|
|
|
|
|
if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
|
2019-04-26 13:59:41 +03:00
|
|
|
NS_SetRequestBlockingReasonIfNull(
|
|
|
|
aLoadInfo, nsILoadInfo::BLOCKING_REASON_CONTENT_POLICY_GENERAL);
|
|
|
|
|
2017-01-03 22:59:30 +03:00
|
|
|
if ((NS_SUCCEEDED(rv) && shouldLoad == nsIContentPolicy::REJECT_TYPE) &&
|
|
|
|
(contentPolicyType == nsIContentPolicy::TYPE_DOCUMENT ||
|
|
|
|
contentPolicyType == nsIContentPolicy::TYPE_SUBDOCUMENT)) {
|
|
|
|
// for docshell loads we might have to return SHOW_ALT.
|
|
|
|
return NS_ERROR_CONTENT_BLOCKED_SHOW_ALT;
|
|
|
|
}
|
2015-07-20 05:12:11 +03:00
|
|
|
return NS_ERROR_CONTENT_BLOCKED;
|
|
|
|
}
|
Bug 1246540 - HSTS Priming Proof of Concept. r=ckerschb, r=mayhemer, r=jld, r=smaug, r=dkeeler, r=jmaher, p=ally
HSTS priming changes the order of mixed-content blocking and HSTS
upgrades, and adds a priming request to check if a mixed-content load is
accesible over HTTPS and the server supports upgrading via the
Strict-Transport-Security header.
Every call site that uses AsyncOpen2 passes through the mixed-content
blocker, and has a LoadInfo. If the mixed-content blocker marks the load as
needing HSTS priming, nsHttpChannel will build and send an HSTS priming
request on the same URI with the scheme upgraded to HTTPS. If the server
allows the upgrade, then channel performs an internal redirect to the HTTPS URI,
otherwise use the result of mixed-content blocker to allow or block the
load.
nsISiteSecurityService adds an optional boolean out parameter to
determine if the HSTS state is already cached for negative assertions.
If the host has been probed within the previous 24 hours, no HSTS
priming check will be sent.
MozReview-Commit-ID: ES1JruCtDdX
--HG--
extra : rebase_source : 2ac6c93c49f2862fc0b9e595eb0598cd1ea4bedf
2016-09-27 18:27:00 +03:00
|
|
|
|
2015-07-20 05:12:11 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2018-09-28 16:06:29 +03:00
|
|
|
static void LogPrincipal(nsIPrincipal* aPrincipal,
|
2020-07-21 20:44:19 +03:00
|
|
|
const nsAString& aPrincipalName,
|
|
|
|
const uint8_t& aNestingLevel) {
|
|
|
|
nsPrintfCString aIndentationString("%*s", aNestingLevel * 2, "");
|
|
|
|
|
2019-12-05 07:44:32 +03:00
|
|
|
if (aPrincipal && aPrincipal->IsSystemPrincipal()) {
|
2018-09-28 16:06:29 +03:00
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Debug,
|
2020-07-21 20:44:19 +03:00
|
|
|
("%s%s: SystemPrincipal\n", aIndentationString.get(),
|
2018-09-28 16:06:29 +03:00
|
|
|
NS_ConvertUTF16toUTF8(aPrincipalName).get()));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (aPrincipal) {
|
|
|
|
if (aPrincipal->GetIsNullPrincipal()) {
|
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Debug,
|
2020-07-21 20:44:19 +03:00
|
|
|
("%s%s: NullPrincipal\n", aIndentationString.get(),
|
2018-09-28 16:06:29 +03:00
|
|
|
NS_ConvertUTF16toUTF8(aPrincipalName).get()));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (aPrincipal->GetIsExpandedPrincipal()) {
|
2019-01-14 17:24:44 +03:00
|
|
|
nsCOMPtr<nsIExpandedPrincipal> expanded(do_QueryInterface(aPrincipal));
|
|
|
|
const nsTArray<nsCOMPtr<nsIPrincipal>>& allowList = expanded->AllowList();
|
2018-10-22 15:49:10 +03:00
|
|
|
nsAutoCString origin;
|
2019-01-14 17:24:44 +03:00
|
|
|
origin.AssignLiteral("[Expanded Principal [");
|
|
|
|
for (size_t i = 0; i < allowList.Length(); ++i) {
|
|
|
|
if (i != 0) {
|
|
|
|
origin.AppendLiteral(", ");
|
|
|
|
}
|
|
|
|
|
|
|
|
nsAutoCString subOrigin;
|
|
|
|
DebugOnly<nsresult> rv = allowList.ElementAt(i)->GetOrigin(subOrigin);
|
|
|
|
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
|
|
|
origin.Append(subOrigin);
|
|
|
|
}
|
|
|
|
origin.AppendLiteral("]]");
|
|
|
|
|
2018-10-22 15:49:10 +03:00
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Debug,
|
2020-07-21 20:44:19 +03:00
|
|
|
("%s%s: %s\n", aIndentationString.get(),
|
|
|
|
NS_ConvertUTF16toUTF8(aPrincipalName).get(), origin.get()));
|
2018-09-28 16:06:29 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
nsAutoCString principalSpec;
|
2019-10-22 19:03:27 +03:00
|
|
|
aPrincipal->GetAsciiSpec(principalSpec);
|
2018-09-28 16:06:29 +03:00
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Debug,
|
2020-07-21 20:44:19 +03:00
|
|
|
("%s%s %s\n", aIndentationString.get(),
|
|
|
|
NS_ConvertUTF16toUTF8(aPrincipalName).get(), principalSpec.get()));
|
2018-09-28 16:06:29 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Debug,
|
2020-07-21 20:44:19 +03:00
|
|
|
("%s%s: nullptr\n", aIndentationString.get(),
|
|
|
|
NS_ConvertUTF16toUTF8(aPrincipalName).get()));
|
2018-09-28 16:06:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void LogSecurityFlags(nsSecurityFlags securityFlags) {
|
|
|
|
struct DebugSecFlagType {
|
|
|
|
unsigned long secFlag;
|
|
|
|
char secTypeStr[128];
|
|
|
|
};
|
|
|
|
static const DebugSecFlagType secTypes[] = {
|
|
|
|
{nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK,
|
|
|
|
"SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK"},
|
2020-07-15 14:20:45 +03:00
|
|
|
{nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_INHERITS_SEC_CONTEXT,
|
|
|
|
"SEC_REQUIRE_SAME_ORIGIN_INHERITS_SEC_CONTEXT"},
|
2018-09-28 16:06:29 +03:00
|
|
|
{nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED,
|
|
|
|
"SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED"},
|
2020-07-15 14:20:45 +03:00
|
|
|
{nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT,
|
|
|
|
"SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT"},
|
|
|
|
{nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
|
|
|
|
"SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL"},
|
|
|
|
{nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT,
|
|
|
|
"SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT"},
|
2018-09-28 16:06:29 +03:00
|
|
|
{nsILoadInfo::SEC_COOKIES_DEFAULT, "SEC_COOKIES_DEFAULT"},
|
|
|
|
{nsILoadInfo::SEC_COOKIES_INCLUDE, "SEC_COOKIES_INCLUDE"},
|
|
|
|
{nsILoadInfo::SEC_COOKIES_SAME_ORIGIN, "SEC_COOKIES_SAME_ORIGIN"},
|
|
|
|
{nsILoadInfo::SEC_COOKIES_OMIT, "SEC_COOKIES_OMIT"},
|
|
|
|
{nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL, "SEC_FORCE_INHERIT_PRINCIPAL"},
|
|
|
|
{nsILoadInfo::SEC_ABOUT_BLANK_INHERITS, "SEC_ABOUT_BLANK_INHERITS"},
|
|
|
|
{nsILoadInfo::SEC_ALLOW_CHROME, "SEC_ALLOW_CHROME"},
|
|
|
|
{nsILoadInfo::SEC_DISALLOW_SCRIPT, "SEC_DISALLOW_SCRIPT"},
|
|
|
|
{nsILoadInfo::SEC_DONT_FOLLOW_REDIRECTS, "SEC_DONT_FOLLOW_REDIRECTS"},
|
|
|
|
{nsILoadInfo::SEC_LOAD_ERROR_PAGE, "SEC_LOAD_ERROR_PAGE"},
|
|
|
|
{nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL_OVERRULE_OWNER,
|
|
|
|
"SEC_FORCE_INHERIT_PRINCIPAL_OVERRULE_OWNER"}};
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2020-02-04 11:38:14 +03:00
|
|
|
for (const DebugSecFlagType& flag : secTypes) {
|
2018-09-28 16:06:29 +03:00
|
|
|
if (securityFlags & flag.secFlag) {
|
2020-07-21 20:44:19 +03:00
|
|
|
// the logging level should be in sync with the logging level in
|
|
|
|
// DebugDoContentSecurityCheck()
|
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Verbose, (" - %s\n", flag.secTypeStr));
|
2018-09-28 16:06:29 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
static void DebugDoContentSecurityCheck(nsIChannel* aChannel,
|
|
|
|
nsILoadInfo* aLoadInfo) {
|
|
|
|
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
|
|
|
|
|
2020-07-21 20:44:19 +03:00
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Debug, ("\n#DebugDoContentSecurityCheck Begin\n"));
|
|
|
|
|
2018-09-28 16:06:29 +03:00
|
|
|
// we only log http channels, unless loglevel is 5.
|
|
|
|
if (httpChannel || MOZ_LOG_TEST(sCSMLog, LogLevel::Verbose)) {
|
|
|
|
nsCOMPtr<nsIURI> channelURI;
|
|
|
|
nsAutoCString channelSpec;
|
|
|
|
nsAutoCString channelMethod;
|
|
|
|
NS_GetFinalChannelURI(aChannel, getter_AddRefs(channelURI));
|
|
|
|
if (channelURI) {
|
|
|
|
channelURI->GetSpec(channelSpec);
|
|
|
|
}
|
|
|
|
|
2020-07-21 20:44:19 +03:00
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Verbose, ("doContentSecurityCheck:\n"));
|
|
|
|
|
2019-08-01 23:44:38 +03:00
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Verbose,
|
2020-07-21 20:44:19 +03:00
|
|
|
(" - channelURI: %s\n", channelSpec.get()));
|
2018-09-28 16:06:29 +03:00
|
|
|
|
|
|
|
// Log HTTP-specific things
|
|
|
|
if (httpChannel) {
|
|
|
|
nsresult rv;
|
|
|
|
rv = httpChannel->GetRequestMethod(channelMethod);
|
|
|
|
if (!NS_FAILED(rv)) {
|
2019-08-01 23:44:38 +03:00
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Verbose,
|
2020-07-21 20:44:19 +03:00
|
|
|
(" - httpMethod: %s\n", channelMethod.get()));
|
2018-09-28 16:06:29 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Log Principals
|
|
|
|
nsCOMPtr<nsIPrincipal> requestPrincipal = aLoadInfo->TriggeringPrincipal();
|
2020-07-21 20:44:19 +03:00
|
|
|
LogPrincipal(aLoadInfo->GetLoadingPrincipal(), u"- loadingPrincipal"_ns, 1);
|
|
|
|
LogPrincipal(requestPrincipal, u"- triggeringPrincipal"_ns, 1);
|
|
|
|
LogPrincipal(aLoadInfo->PrincipalToInherit(), u"- principalToInherit"_ns,
|
|
|
|
1);
|
2018-09-28 16:06:29 +03:00
|
|
|
|
|
|
|
// Log Redirect Chain
|
2020-07-21 20:44:19 +03:00
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Verbose, (" - redirectChain:\n"));
|
2018-09-28 16:06:29 +03:00
|
|
|
for (nsIRedirectHistoryEntry* redirectHistoryEntry :
|
|
|
|
aLoadInfo->RedirectChain()) {
|
|
|
|
nsCOMPtr<nsIPrincipal> principal;
|
|
|
|
redirectHistoryEntry->GetPrincipal(getter_AddRefs(principal));
|
2020-07-21 20:44:19 +03:00
|
|
|
LogPrincipal(principal, u"-"_ns, 2);
|
2018-09-28 16:06:29 +03:00
|
|
|
}
|
|
|
|
|
2019-08-01 23:44:38 +03:00
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Verbose,
|
2020-07-21 20:44:19 +03:00
|
|
|
(" - internalContentPolicyType: %s\n",
|
|
|
|
NS_CP_ContentTypeName(aLoadInfo->InternalContentPolicyType())));
|
2019-08-01 23:44:38 +03:00
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Verbose,
|
2020-07-21 20:44:19 +03:00
|
|
|
(" - externalContentPolicyType: %s\n",
|
|
|
|
NS_CP_ContentTypeName(aLoadInfo->GetExternalContentPolicyType())));
|
2019-08-01 23:44:38 +03:00
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Verbose,
|
2020-07-21 20:44:19 +03:00
|
|
|
(" - upgradeInsecureRequests: %s\n",
|
2018-09-28 16:06:29 +03:00
|
|
|
aLoadInfo->GetUpgradeInsecureRequests() ? "true" : "false"));
|
2019-08-01 23:44:38 +03:00
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Verbose,
|
2020-07-21 20:44:19 +03:00
|
|
|
(" - initalSecurityChecksDone: %s\n",
|
2018-09-28 16:06:29 +03:00
|
|
|
aLoadInfo->GetInitialSecurityCheckDone() ? "true" : "false"));
|
2020-05-20 16:01:35 +03:00
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Verbose,
|
2020-07-21 20:44:19 +03:00
|
|
|
(" - allowDeprecatedSystemRequests: %s\n",
|
2020-05-20 16:01:35 +03:00
|
|
|
aLoadInfo->GetAllowDeprecatedSystemRequests() ? "true" : "false"));
|
2018-09-28 16:06:29 +03:00
|
|
|
|
|
|
|
// Log CSPrequestPrincipal
|
2019-05-22 02:14:27 +03:00
|
|
|
nsCOMPtr<nsIContentSecurityPolicy> csp = aLoadInfo->GetCsp();
|
2020-07-21 20:44:19 +03:00
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Debug, (" - CSP:"));
|
2018-09-28 16:06:29 +03:00
|
|
|
if (csp) {
|
|
|
|
nsAutoString parsedPolicyStr;
|
|
|
|
uint32_t count = 0;
|
|
|
|
csp->GetPolicyCount(&count);
|
|
|
|
for (uint32_t i = 0; i < count; ++i) {
|
|
|
|
csp->GetPolicyString(i, parsedPolicyStr);
|
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Debug,
|
2020-07-21 20:44:19 +03:00
|
|
|
(" - %s\n", NS_ConvertUTF16toUTF8(parsedPolicyStr).get()));
|
2018-09-28 16:06:29 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Security Flags
|
2020-07-21 20:44:19 +03:00
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Verbose, (" - securityFlags:"));
|
2018-09-28 16:06:29 +03:00
|
|
|
LogSecurityFlags(aLoadInfo->GetSecurityFlags());
|
2020-07-21 20:44:19 +03:00
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Debug, ("\n#DebugDoContentSecurityCheck End\n"));
|
2018-09-28 16:06:29 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-08 16:11:57 +03:00
|
|
|
/* static */
|
|
|
|
void nsContentSecurityManager::MeasureUnexpectedPrivilegedLoads(
|
|
|
|
nsIURI* aFinalURI, nsContentPolicyType aContentPolicyType,
|
2020-07-08 23:15:59 +03:00
|
|
|
const nsACString& aRemoteType) {
|
2020-07-08 16:11:57 +03:00
|
|
|
if (!StaticPrefs::dom_security_unexpected_system_load_telemetry_enabled()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
nsAutoCString uriString;
|
|
|
|
if (aFinalURI) {
|
|
|
|
aFinalURI->GetAsciiSpec(uriString);
|
|
|
|
} else {
|
|
|
|
uriString.AssignLiteral("");
|
|
|
|
}
|
|
|
|
FilenameTypeAndDetails fileNameTypeAndDetails =
|
|
|
|
nsContentSecurityUtils::FilenameToFilenameType(
|
|
|
|
NS_ConvertUTF8toUTF16(uriString), false);
|
|
|
|
|
|
|
|
nsCString loggedFileDetails = "unknown"_ns;
|
|
|
|
if (fileNameTypeAndDetails.second.isSome()) {
|
|
|
|
loggedFileDetails.Assign(
|
|
|
|
NS_ConvertUTF16toUTF8(fileNameTypeAndDetails.second.value()));
|
|
|
|
}
|
|
|
|
// sanitize remoteType because it may contain sensitive
|
|
|
|
// info, like URLs. e.g. `webIsolated=https://example.com`
|
2020-07-08 23:15:59 +03:00
|
|
|
nsAutoCString loggedRemoteType(dom::RemoteTypePrefix(aRemoteType));
|
2020-07-08 16:11:57 +03:00
|
|
|
nsAutoCString loggedContentType(NS_CP_ContentTypeName(aContentPolicyType));
|
|
|
|
|
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Debug, ("UnexpectedPrivilegedLoadTelemetry:\n"));
|
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Debug,
|
|
|
|
("- contentType: %s\n", loggedContentType.get()));
|
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Debug,
|
|
|
|
("- URL (not to be reported): %s\n", uriString.get()));
|
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Debug,
|
|
|
|
("- remoteType: %s\n", loggedRemoteType.get()));
|
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Debug,
|
|
|
|
("- fileInfo: %s\n", fileNameTypeAndDetails.first.get()));
|
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Debug,
|
|
|
|
("- fileDetails: %s\n\n", loggedFileDetails.get()));
|
|
|
|
|
|
|
|
// Send Telemetry
|
|
|
|
auto extra = Some<nsTArray<EventExtraEntry>>(
|
|
|
|
{EventExtraEntry{"contenttype"_ns, loggedContentType},
|
|
|
|
EventExtraEntry{"remotetype"_ns, loggedRemoteType},
|
|
|
|
EventExtraEntry{"filedetails"_ns, loggedFileDetails}});
|
|
|
|
|
|
|
|
if (!sTelemetryEventEnabled.exchange(true)) {
|
|
|
|
Telemetry::SetEventRecordingEnabled("security"_ns, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
Telemetry::EventID eventType =
|
|
|
|
Telemetry::EventID::Security_Unexpectedload_Systemprincipal;
|
|
|
|
Telemetry::RecordEvent(eventType, mozilla::Some(fileNameTypeAndDetails.first),
|
|
|
|
extra);
|
|
|
|
}
|
|
|
|
|
2019-12-02 13:45:23 +03:00
|
|
|
/* static */
|
2020-01-17 20:29:47 +03:00
|
|
|
nsresult nsContentSecurityManager::CheckAllowLoadInSystemPrivilegedContext(
|
2019-04-10 17:20:12 +03:00
|
|
|
nsIChannel* aChannel) {
|
2020-01-17 20:29:47 +03:00
|
|
|
// Check and assert that we never allow remote documents/scripts (http:,
|
|
|
|
// https:, ...) to load in system privileged contexts.
|
2019-04-10 17:20:12 +03:00
|
|
|
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
|
|
|
|
|
2020-01-17 20:29:47 +03:00
|
|
|
// nothing to do here if we are not loading a resource into a
|
|
|
|
// system prvileged context.
|
2020-04-06 21:57:36 +03:00
|
|
|
if (!loadInfo->GetLoadingPrincipal() ||
|
|
|
|
!loadInfo->GetLoadingPrincipal()->IsSystemPrincipal()) {
|
2019-12-02 13:45:23 +03:00
|
|
|
return NS_OK;
|
2019-04-10 17:20:12 +03:00
|
|
|
}
|
2020-05-20 16:01:35 +03:00
|
|
|
// loads with the allow flag are waived through
|
|
|
|
// until refactored (e.g., Shavar, OCSP)
|
2020-05-20 06:35:48 +03:00
|
|
|
if (loadInfo->GetAllowDeprecatedSystemRequests()) {
|
2020-05-18 13:05:12 +03:00
|
|
|
return NS_OK;
|
2020-05-18 12:19:28 +03:00
|
|
|
}
|
2020-05-18 16:38:58 +03:00
|
|
|
|
2020-05-20 06:35:48 +03:00
|
|
|
nsContentPolicyType contentPolicyType =
|
|
|
|
loadInfo->GetExternalContentPolicyType();
|
|
|
|
|
2020-05-20 16:01:35 +03:00
|
|
|
// allowing some fetches due to their lowered risk
|
|
|
|
// i.e., data & downloads fetches do limited parsing, no rendering
|
|
|
|
// remote images are too widely used (favicons, about:addons etc.)
|
|
|
|
if ((contentPolicyType == nsIContentPolicy::TYPE_FETCH) ||
|
|
|
|
(contentPolicyType == nsIContentPolicy::TYPE_XMLHTTPREQUEST) ||
|
|
|
|
(contentPolicyType == nsIContentPolicy::TYPE_WEBSOCKET) ||
|
|
|
|
(contentPolicyType == nsIContentPolicy::TYPE_SAVEAS_DOWNLOAD) ||
|
|
|
|
(contentPolicyType == nsIContentPolicy::TYPE_IMAGE)) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Allow the user interface (e.g., schemes like chrome, resource)
|
|
|
|
nsCOMPtr<nsIURI> finalURI;
|
|
|
|
NS_GetFinalChannelURI(aChannel, getter_AddRefs(finalURI));
|
|
|
|
bool isUiResource = false;
|
|
|
|
if (NS_SUCCEEDED(NS_URIChainHasFlags(
|
|
|
|
finalURI, nsIProtocolHandler::URI_IS_UI_RESOURCE, &isUiResource)) &&
|
|
|
|
isUiResource) {
|
2020-05-18 16:38:58 +03:00
|
|
|
return NS_OK;
|
2020-05-18 13:59:12 +03:00
|
|
|
}
|
2020-05-20 16:01:35 +03:00
|
|
|
// For about: and extension-based URIs, which don't get
|
|
|
|
// URI_IS_UI_RESOURCE, first remove layers of view-source:, if present.
|
|
|
|
while (finalURI && finalURI->SchemeIs("view-source")) {
|
|
|
|
nsCOMPtr<nsINestedURI> nested = do_QueryInterface(finalURI);
|
|
|
|
if (nested) {
|
|
|
|
nested->GetInnerURI(getter_AddRefs(finalURI));
|
|
|
|
}
|
|
|
|
}
|
2020-07-08 16:11:57 +03:00
|
|
|
|
2020-07-08 23:15:59 +03:00
|
|
|
nsAutoCString remoteType;
|
2020-07-08 16:11:57 +03:00
|
|
|
if (XRE_IsParentProcess()) {
|
|
|
|
nsCOMPtr<nsIParentChannel> parentChannel;
|
|
|
|
NS_QueryNotificationCallbacks(aChannel, parentChannel);
|
|
|
|
if (parentChannel) {
|
|
|
|
parentChannel->GetRemoteType(remoteType);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
remoteType.Assign(
|
|
|
|
mozilla::dom::ContentChild::GetSingleton()->GetRemoteType());
|
|
|
|
}
|
|
|
|
|
2020-05-20 16:01:35 +03:00
|
|
|
// This is our escape hatch, if things break in release.
|
|
|
|
// We expect to remove the pref in bug 1638770
|
|
|
|
bool cancelNonLocalSystemPrincipal = StaticPrefs::
|
|
|
|
security_cancel_non_local_loads_triggered_by_systemprincipal();
|
2020-05-20 06:35:48 +03:00
|
|
|
|
2020-05-20 16:01:35 +03:00
|
|
|
// GetInnerURI can return null for malformed nested URIs like moz-icon:trash
|
2020-07-08 16:11:57 +03:00
|
|
|
if (!finalURI) {
|
|
|
|
MeasureUnexpectedPrivilegedLoads(finalURI, contentPolicyType, remoteType);
|
|
|
|
if (cancelNonLocalSystemPrincipal) {
|
|
|
|
aChannel->Cancel(NS_ERROR_CONTENT_BLOCKED);
|
|
|
|
return NS_ERROR_CONTENT_BLOCKED;
|
|
|
|
}
|
2020-05-20 16:01:35 +03:00
|
|
|
}
|
|
|
|
// loads of userContent.css during startup and tests that show up as file:
|
|
|
|
if (finalURI->SchemeIs("file")) {
|
|
|
|
if ((contentPolicyType == nsIContentPolicy::TYPE_STYLESHEET) ||
|
|
|
|
(contentPolicyType == nsIContentPolicy::TYPE_OTHER)) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// (1)loads from within omni.ja and system add-ons use jar:
|
|
|
|
// this is safe to allow, because we do not support remote jar.
|
|
|
|
// (2) about: resources are always allowed: they are part of the build.
|
|
|
|
// (3) extensions are signed or the user has made bad decisions.
|
|
|
|
if (finalURI->SchemeIs("jar") || finalURI->SchemeIs("about") ||
|
|
|
|
finalURI->SchemeIs("moz-extension")) {
|
2020-05-20 06:35:48 +03:00
|
|
|
return NS_OK;
|
2020-05-19 11:55:06 +03:00
|
|
|
}
|
2020-07-08 16:11:57 +03:00
|
|
|
// Telemetry for unexpected privileged loads.
|
|
|
|
// pref check & data sanitization happens in the called function
|
|
|
|
if (finalURI) {
|
|
|
|
MeasureUnexpectedPrivilegedLoads(finalURI, contentPolicyType, remoteType);
|
|
|
|
}
|
2020-01-17 20:29:47 +03:00
|
|
|
|
2020-05-20 16:01:35 +03:00
|
|
|
// Relaxing restrictions for our test suites:
|
|
|
|
// (1) AreNonLocalConnectionsDisabled() disables network, so http://mochitest
|
|
|
|
// is actually local and allowed. (2) The marionette test framework uses
|
|
|
|
// injections and data URLs to execute scripts, checking for the environment
|
|
|
|
// variable breaks the attack but not the tests.
|
|
|
|
if (xpc::AreNonLocalConnectionsDisabled() ||
|
|
|
|
mozilla::EnvHasValue("MOZ_MARIONETTE")) {
|
2019-04-10 17:20:12 +03:00
|
|
|
bool disallowSystemPrincipalRemoteDocuments = Preferences::GetBool(
|
|
|
|
"security.disallow_non_local_systemprincipal_in_tests");
|
|
|
|
if (disallowSystemPrincipalRemoteDocuments) {
|
|
|
|
// our own mochitest needs NS_ASSERTION instead of MOZ_ASSERT
|
|
|
|
NS_ASSERTION(false, "SystemPrincipal must not load remote documents.");
|
2019-12-02 13:45:23 +03:00
|
|
|
aChannel->Cancel(NS_ERROR_CONTENT_BLOCKED);
|
|
|
|
return NS_ERROR_CONTENT_BLOCKED;
|
2019-04-10 17:20:12 +03:00
|
|
|
}
|
|
|
|
// but other mochitest are exempt from this
|
2019-12-02 13:45:23 +03:00
|
|
|
return NS_OK;
|
2019-04-10 17:20:12 +03:00
|
|
|
}
|
2020-03-05 21:43:04 +03:00
|
|
|
|
|
|
|
nsAutoCString requestedURL;
|
|
|
|
finalURI->GetAsciiSpec(requestedURL);
|
2020-05-20 16:01:35 +03:00
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Warning,
|
|
|
|
("SystemPrincipal must not load remote documents. URL: %s, type %d",
|
|
|
|
requestedURL.get(), contentPolicyType));
|
|
|
|
|
|
|
|
if (cancelNonLocalSystemPrincipal) {
|
|
|
|
MOZ_ASSERT(false, "SystemPrincipal must not load remote documents.");
|
|
|
|
aChannel->Cancel(NS_ERROR_CONTENT_BLOCKED);
|
|
|
|
return NS_ERROR_CONTENT_BLOCKED;
|
|
|
|
}
|
|
|
|
return NS_OK;
|
2019-04-10 17:20:12 +03:00
|
|
|
}
|
|
|
|
|
2020-03-20 11:25:18 +03:00
|
|
|
/*
|
|
|
|
* Every protocol handler must set one of the five security flags
|
|
|
|
* defined in nsIProtocolHandler - if not - deny the load.
|
|
|
|
*/
|
|
|
|
nsresult nsContentSecurityManager::CheckChannelHasProtocolSecurityFlag(
|
|
|
|
nsIChannel* aChannel) {
|
|
|
|
nsCOMPtr<nsIURI> uri;
|
|
|
|
nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
nsAutoCString scheme;
|
|
|
|
rv = uri->GetScheme(scheme);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIIOService> ios = do_GetIOService(&rv);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIProtocolHandler> handler;
|
|
|
|
rv = ios->GetProtocolHandler(scheme.get(), getter_AddRefs(handler));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
uint32_t flags;
|
|
|
|
rv = handler->DoGetProtocolFlags(uri, &flags);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
uint32_t securityFlagsSet = 0;
|
|
|
|
if (flags & nsIProtocolHandler::URI_LOADABLE_BY_ANYONE) {
|
|
|
|
securityFlagsSet += 1;
|
|
|
|
}
|
|
|
|
if (flags & nsIProtocolHandler::URI_DANGEROUS_TO_LOAD) {
|
|
|
|
securityFlagsSet += 1;
|
|
|
|
}
|
|
|
|
if (flags & nsIProtocolHandler::URI_IS_UI_RESOURCE) {
|
|
|
|
securityFlagsSet += 1;
|
|
|
|
}
|
|
|
|
if (flags & nsIProtocolHandler::URI_IS_LOCAL_FILE) {
|
|
|
|
securityFlagsSet += 1;
|
|
|
|
}
|
|
|
|
if (flags & nsIProtocolHandler::URI_LOADABLE_BY_SUBSUMERS) {
|
|
|
|
securityFlagsSet += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure that only "1" valid security flags is set.
|
|
|
|
if (securityFlagsSet == 1) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_ASSERT(false, "protocol must use one valid security flag");
|
|
|
|
return NS_ERROR_CONTENT_BLOCKED;
|
|
|
|
}
|
|
|
|
|
2015-07-20 05:12:11 +03:00
|
|
|
/*
|
|
|
|
* Based on the security flags provided in the loadInfo of the channel,
|
|
|
|
* doContentSecurityCheck() performs the following content security checks
|
|
|
|
* before opening the channel:
|
|
|
|
*
|
|
|
|
* (1) Same Origin Policy Check (if applicable)
|
|
|
|
* (2) Allow Cross Origin but perform sanity checks whether a principal
|
|
|
|
* is allowed to access the following URL.
|
|
|
|
* (3) Perform CORS check (if applicable)
|
|
|
|
* (4) ContentPolicy checks (Content-Security-Policy, Mixed Content, ...)
|
|
|
|
*
|
|
|
|
* @param aChannel
|
|
|
|
* The channel to perform the security checks on.
|
|
|
|
* @param aInAndOutListener
|
2019-02-12 19:08:25 +03:00
|
|
|
* The streamListener that is passed to channel->AsyncOpen() that is now
|
2015-07-20 05:12:11 +03:00
|
|
|
* potentially wrappend within nsCORSListenerProxy() and becomes the
|
|
|
|
* corsListener that now needs to be set as new streamListener on the channel.
|
|
|
|
*/
|
|
|
|
nsresult nsContentSecurityManager::doContentSecurityCheck(
|
|
|
|
nsIChannel* aChannel, nsCOMPtr<nsIStreamListener>& aInAndOutListener) {
|
|
|
|
NS_ENSURE_ARG(aChannel);
|
2019-02-20 15:27:25 +03:00
|
|
|
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
|
2019-08-01 23:44:38 +03:00
|
|
|
if (MOZ_UNLIKELY(MOZ_LOG_TEST(sCSMLog, LogLevel::Verbose))) {
|
2018-09-28 16:06:29 +03:00
|
|
|
DebugDoContentSecurityCheck(aChannel, loadInfo);
|
|
|
|
}
|
|
|
|
|
2020-01-17 20:29:47 +03:00
|
|
|
nsresult rv = CheckAllowLoadInSystemPrivilegedContext(aChannel);
|
2019-12-02 13:45:23 +03:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2019-04-10 17:20:12 +03:00
|
|
|
|
2020-03-20 11:25:18 +03:00
|
|
|
rv = CheckChannelHasProtocolSecurityFlag(aChannel);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2015-12-07 02:33:14 +03:00
|
|
|
// if dealing with a redirected channel then we have already installed
|
|
|
|
// streamlistener and redirect proxies and so we are done.
|
|
|
|
if (loadInfo->GetInitialSecurityCheckDone()) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2015-07-20 05:12:11 +03:00
|
|
|
// make sure that only one of the five security flags is set in the loadinfo
|
|
|
|
// e.g. do not require same origin and allow cross origin at the same time
|
2019-12-02 13:45:23 +03:00
|
|
|
rv = ValidateSecurityFlags(loadInfo);
|
2015-07-20 05:12:11 +03:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2015-12-07 02:33:14 +03:00
|
|
|
if (loadInfo->GetSecurityMode() ==
|
2020-07-15 14:20:45 +03:00
|
|
|
nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT) {
|
2015-12-07 02:33:14 +03:00
|
|
|
rv = DoCORSChecks(aChannel, loadInfo, aInAndOutListener);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
2015-12-07 02:33:15 +03:00
|
|
|
|
|
|
|
rv = CheckChannel(aChannel);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2015-12-07 02:33:14 +03:00
|
|
|
|
|
|
|
// Perform all ContentPolicy checks (MixedContent, CSP, ...)
|
2016-05-17 13:04:11 +03:00
|
|
|
rv = DoContentSecurityChecks(aChannel, loadInfo);
|
2015-12-07 02:33:14 +03:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2018-04-06 01:27:02 +03:00
|
|
|
// Apply this after CSP to match Chrome.
|
|
|
|
rv = CheckFTPSubresourceLoad(aChannel);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2015-12-07 02:33:14 +03:00
|
|
|
// now lets set the initalSecurityFlag for subsequent calls
|
2016-08-12 08:19:29 +03:00
|
|
|
loadInfo->SetInitialSecurityCheckDone(true);
|
2015-12-07 02:33:14 +03:00
|
|
|
|
|
|
|
// all security checks passed - lets allow the load
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsContentSecurityManager::AsyncOnChannelRedirect(
|
|
|
|
nsIChannel* aOldChannel, nsIChannel* aNewChannel, uint32_t aRedirFlags,
|
|
|
|
nsIAsyncVerifyRedirectCallback* aCb) {
|
2019-11-07 22:13:59 +03:00
|
|
|
// Since we compare the principal from the loadInfo to the URI's
|
|
|
|
// princicpal, it's possible that the checks fail when doing an internal
|
|
|
|
// redirect. We can just return early instead, since we should never
|
|
|
|
// need to block an internal redirect.
|
|
|
|
if (aRedirFlags & nsIChannelEventSink::REDIRECT_INTERNAL) {
|
|
|
|
aCb->OnRedirectVerifyCallback(NS_OK);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2019-02-20 15:27:25 +03:00
|
|
|
nsCOMPtr<nsILoadInfo> loadInfo = aOldChannel->LoadInfo();
|
|
|
|
nsresult rv = CheckChannel(aNewChannel);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
rv = CheckFTPSubresourceLoad(aNewChannel);
|
|
|
|
}
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
aOldChannel->Cancel(rv);
|
|
|
|
return rv;
|
2015-12-07 02:33:14 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Also verify that the redirecting server is allowed to redirect to the
|
|
|
|
// given URI
|
|
|
|
nsCOMPtr<nsIPrincipal> oldPrincipal;
|
|
|
|
nsContentUtils::GetSecurityManager()->GetChannelResultPrincipal(
|
|
|
|
aOldChannel, getter_AddRefs(oldPrincipal));
|
|
|
|
|
|
|
|
nsCOMPtr<nsIURI> newURI;
|
2017-07-13 06:51:00 +03:00
|
|
|
Unused << NS_GetFinalChannelURI(aNewChannel, getter_AddRefs(newURI));
|
|
|
|
NS_ENSURE_STATE(oldPrincipal && newURI);
|
2015-12-07 02:33:14 +03:00
|
|
|
|
2018-01-23 11:57:47 +03:00
|
|
|
// Do not allow insecure redirects to data: URIs
|
2018-02-18 21:52:52 +03:00
|
|
|
if (!AllowInsecureRedirectToDataURI(aNewChannel)) {
|
|
|
|
// cancel the old channel and return an error
|
|
|
|
aOldChannel->Cancel(NS_ERROR_CONTENT_BLOCKED);
|
|
|
|
return NS_ERROR_CONTENT_BLOCKED;
|
2018-01-23 11:57:47 +03:00
|
|
|
}
|
|
|
|
|
2015-12-07 02:33:14 +03:00
|
|
|
const uint32_t flags =
|
|
|
|
nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT |
|
|
|
|
nsIScriptSecurityManager::DISALLOW_SCRIPT;
|
2019-02-20 15:27:25 +03:00
|
|
|
rv = nsContentUtils::GetSecurityManager()->CheckLoadURIWithPrincipal(
|
2019-12-12 19:41:19 +03:00
|
|
|
oldPrincipal, newURI, flags, loadInfo->GetInnerWindowID());
|
Bug 1246540 - HSTS Priming Proof of Concept. r=ckerschb, r=mayhemer, r=jld, r=smaug, r=dkeeler, r=jmaher, p=ally
HSTS priming changes the order of mixed-content blocking and HSTS
upgrades, and adds a priming request to check if a mixed-content load is
accesible over HTTPS and the server supports upgrading via the
Strict-Transport-Security header.
Every call site that uses AsyncOpen2 passes through the mixed-content
blocker, and has a LoadInfo. If the mixed-content blocker marks the load as
needing HSTS priming, nsHttpChannel will build and send an HSTS priming
request on the same URI with the scheme upgraded to HTTPS. If the server
allows the upgrade, then channel performs an internal redirect to the HTTPS URI,
otherwise use the result of mixed-content blocker to allow or block the
load.
nsISiteSecurityService adds an optional boolean out parameter to
determine if the HSTS state is already cached for negative assertions.
If the host has been probed within the previous 24 hours, no HSTS
priming check will be sent.
MozReview-Commit-ID: ES1JruCtDdX
--HG--
extra : rebase_source : 2ac6c93c49f2862fc0b9e595eb0598cd1ea4bedf
2016-09-27 18:27:00 +03:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2015-12-07 02:33:14 +03:00
|
|
|
|
|
|
|
aCb->OnRedirectVerifyCallback(NS_OK);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2015-12-07 02:33:15 +03:00
|
|
|
static void AddLoadFlags(nsIRequest* aRequest, nsLoadFlags aNewFlags) {
|
|
|
|
nsLoadFlags flags;
|
|
|
|
aRequest->GetLoadFlags(&flags);
|
|
|
|
flags |= aNewFlags;
|
|
|
|
aRequest->SetLoadFlags(flags);
|
|
|
|
}
|
|
|
|
|
2015-12-07 02:33:14 +03:00
|
|
|
/*
|
|
|
|
* Check that this channel passes all security checks. Returns an error code
|
|
|
|
* if this requesst should not be permitted.
|
|
|
|
*/
|
|
|
|
nsresult nsContentSecurityManager::CheckChannel(nsIChannel* aChannel) {
|
2019-02-20 15:27:25 +03:00
|
|
|
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
|
2015-12-07 02:33:15 +03:00
|
|
|
nsCOMPtr<nsIURI> uri;
|
|
|
|
nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
// Handle cookie policies
|
|
|
|
uint32_t cookiePolicy = loadInfo->GetCookiePolicy();
|
|
|
|
if (cookiePolicy == nsILoadInfo::SEC_COOKIES_SAME_ORIGIN) {
|
2016-04-14 02:30:28 +03:00
|
|
|
// We shouldn't have the SEC_COOKIES_SAME_ORIGIN flag for top level loads
|
|
|
|
MOZ_ASSERT(loadInfo->GetExternalContentPolicyType() !=
|
|
|
|
nsIContentPolicy::TYPE_DOCUMENT);
|
2020-04-06 21:57:36 +03:00
|
|
|
nsIPrincipal* loadingPrincipal = loadInfo->GetLoadingPrincipal();
|
2015-12-07 02:33:15 +03:00
|
|
|
|
2019-12-13 09:24:12 +03:00
|
|
|
// It doesn't matter what we pass for the second, data-inherits, argument.
|
2015-12-07 02:33:15 +03:00
|
|
|
// Any protocol which inherits won't pay attention to cookies anyway.
|
2019-12-13 09:24:12 +03:00
|
|
|
rv = loadingPrincipal->CheckMayLoad(uri, false);
|
2015-12-07 02:33:15 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
AddLoadFlags(aChannel, nsIRequest::LOAD_ANONYMOUS);
|
|
|
|
}
|
|
|
|
} else if (cookiePolicy == nsILoadInfo::SEC_COOKIES_OMIT) {
|
|
|
|
AddLoadFlags(aChannel, nsIRequest::LOAD_ANONYMOUS);
|
|
|
|
}
|
|
|
|
|
2015-09-15 04:59:35 +03:00
|
|
|
nsSecurityFlags securityMode = loadInfo->GetSecurityMode();
|
2015-12-07 02:33:15 +03:00
|
|
|
|
|
|
|
// CORS mode is handled by nsCORSListenerProxy
|
2020-07-15 14:20:45 +03:00
|
|
|
if (securityMode == nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT) {
|
2015-12-07 02:33:15 +03:00
|
|
|
if (NS_HasBeenCrossOrigin(aChannel)) {
|
|
|
|
loadInfo->MaybeIncreaseTainting(LoadTainting::CORS);
|
|
|
|
}
|
2015-12-07 02:33:14 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2016-03-19 02:14:03 +03:00
|
|
|
// Allow subresource loads if TriggeringPrincipal is the SystemPrincipal.
|
2019-12-05 07:44:32 +03:00
|
|
|
if (loadInfo->TriggeringPrincipal()->IsSystemPrincipal() &&
|
2016-03-19 02:14:03 +03:00
|
|
|
loadInfo->GetExternalContentPolicyType() !=
|
|
|
|
nsIContentPolicy::TYPE_DOCUMENT &&
|
|
|
|
loadInfo->GetExternalContentPolicyType() !=
|
|
|
|
nsIContentPolicy::TYPE_SUBDOCUMENT) {
|
2016-03-02 03:11:37 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2015-09-15 04:59:35 +03:00
|
|
|
// if none of the REQUIRE_SAME_ORIGIN flags are set, then SOP does not apply
|
2020-07-15 14:20:45 +03:00
|
|
|
if ((securityMode ==
|
|
|
|
nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_INHERITS_SEC_CONTEXT) ||
|
2015-09-15 04:59:35 +03:00
|
|
|
(securityMode == nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED)) {
|
2015-12-07 02:33:15 +03:00
|
|
|
rv = DoSOPChecks(uri, loadInfo, aChannel);
|
2015-09-15 04:59:35 +03:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
2015-07-20 05:12:11 +03:00
|
|
|
|
2020-07-15 14:20:45 +03:00
|
|
|
if ((securityMode ==
|
|
|
|
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT) ||
|
|
|
|
(securityMode ==
|
|
|
|
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL)) {
|
2015-12-07 02:33:15 +03:00
|
|
|
if (NS_HasBeenCrossOrigin(aChannel)) {
|
2018-04-23 19:43:36 +03:00
|
|
|
NS_ENSURE_FALSE(loadInfo->GetDontFollowRedirects(), NS_ERROR_DOM_BAD_URI);
|
2015-12-07 02:33:15 +03:00
|
|
|
loadInfo->MaybeIncreaseTainting(LoadTainting::Opaque);
|
|
|
|
}
|
2015-09-15 04:59:35 +03:00
|
|
|
// Please note that DoCheckLoadURIChecks should only be enforced for
|
2020-07-15 14:20:45 +03:00
|
|
|
// cross origin requests. If the flag SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT
|
|
|
|
// is set within the loadInfo, then then CheckLoadURIWithPrincipal is
|
|
|
|
// performed within nsCorsListenerProxy
|
2015-12-07 02:33:14 +03:00
|
|
|
rv = DoCheckLoadURIChecks(uri, loadInfo);
|
2015-12-05 18:34:47 +03:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2017-02-03 06:49:07 +03:00
|
|
|
// TODO: Bug 1371237
|
|
|
|
// consider calling SetBlockedRequest in
|
|
|
|
// nsContentSecurityManager::CheckChannel
|
2015-12-05 18:34:47 +03:00
|
|
|
}
|
|
|
|
|
2015-07-20 05:12:11 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2015-09-18 19:27:15 +03:00
|
|
|
|
|
|
|
// ==== nsIContentSecurityManager implementation =====
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsContentSecurityManager::PerformSecurityCheck(
|
|
|
|
nsIChannel* aChannel, nsIStreamListener* aStreamListener,
|
|
|
|
nsIStreamListener** outStreamListener) {
|
|
|
|
nsCOMPtr<nsIStreamListener> inAndOutListener = aStreamListener;
|
|
|
|
nsresult rv = doContentSecurityCheck(aChannel, inAndOutListener);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
inAndOutListener.forget(outStreamListener);
|
|
|
|
return NS_OK;
|
|
|
|
}
|