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/. */
|
|
|
|
|
2015-07-20 05:12:11 +03:00
|
|
|
#include "nsContentSecurityManager.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"
|
2019-01-29 11:03:06 +03:00
|
|
|
#include "nsCDefaultURIFixup.h"
|
2017-01-03 22:59:30 +03:00
|
|
|
#include "nsIURIFixup.h"
|
2017-02-03 06:49:07 +03:00
|
|
|
#include "nsIImageLoadingContent.h"
|
2018-09-28 16:06:29 +03:00
|
|
|
#include "nsIRedirectHistoryEntry.h"
|
2017-02-03 06:49:07 +03:00
|
|
|
|
2019-01-03 23:55:38 +03:00
|
|
|
#include "mozilla/BasePrincipal.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"
|
2017-11-03 15:23:11 +03:00
|
|
|
#include "mozilla/dom/TabChild.h"
|
2018-09-28 16:06:29 +03:00
|
|
|
#include "mozilla/Logging.h"
|
|
|
|
|
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");
|
|
|
|
|
2017-11-03 15:23:11 +03:00
|
|
|
/* static */ bool nsContentSecurityManager::AllowTopLevelNavigationToDataURI(
|
|
|
|
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
|
|
|
|
// data: URI the triggeringPrincipal is a codeBasePrincipal, or
|
|
|
|
// 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
|
|
|
|
// using a codeBasePrincipal, but we want to block those loads.
|
|
|
|
if (!mozilla::net::nsIOService::BlockToplevelDataUriNavigations()) {
|
|
|
|
return true;
|
|
|
|
}
|
2017-11-03 15:23:11 +03:00
|
|
|
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
|
|
|
|
if (!loadInfo) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
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);
|
2017-09-06 10:33:10 +03:00
|
|
|
bool isDataURI =
|
2017-11-03 15:23:11 +03:00
|
|
|
(NS_SUCCEEDED(uri->SchemeIs("data", &isDataURI)) && isDataURI);
|
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;
|
2018-09-07 17:47:51 +03:00
|
|
|
rv = nsDataHandler::ParseURI(spec, contentType, nullptr, base64, nullptr);
|
2017-11-13 23:25:02 +03:00
|
|
|
NS_ENSURE_SUCCESS(rv, true);
|
|
|
|
|
2017-09-06 17:27:05 +03:00
|
|
|
// Whitelist data: images as long as they are not SVGs
|
2017-11-13 23:25:02 +03:00
|
|
|
if (StringBeginsWith(contentType, NS_LITERAL_CSTRING("image/")) &&
|
|
|
|
!contentType.EqualsLiteral("image/svg+xml")) {
|
2017-09-06 17:27:05 +03:00
|
|
|
return true;
|
|
|
|
}
|
2017-11-13 23:25:02 +03:00
|
|
|
// Whitelist all plain text types as well as data: PDFs.
|
|
|
|
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() &&
|
|
|
|
nsContentUtils::IsSystemPrincipal(loadInfo->TriggeringPrincipal()) &&
|
|
|
|
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();
|
|
|
|
nsCOMPtr<nsITabChild> tabChild = do_QueryInterface(context);
|
2019-01-02 16:05:23 +03:00
|
|
|
nsCOMPtr<Document> doc;
|
2017-11-03 15:23:11 +03:00
|
|
|
if (tabChild) {
|
|
|
|
doc = static_cast<mozilla::dom::TabChild*>(tabChild.get())->GetDocument();
|
|
|
|
}
|
2017-09-12 08:06:38 +03:00
|
|
|
NS_ConvertUTF8toUTF16 specUTF16(NS_UnescapeURL(dataSpec));
|
2017-09-06 10:33:10 +03:00
|
|
|
const char16_t* params[] = {specUTF16.get()};
|
|
|
|
nsContentUtils::ReportToConsole(
|
|
|
|
nsIScriptError::warningFlag, NS_LITERAL_CSTRING("DATA_URI_BLOCKED"), doc,
|
|
|
|
nsContentUtils::eSECURITY_PROPERTIES, "BlockTopLevelDataURINavigation",
|
|
|
|
params, ArrayLength(params));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-02-18 21:52:52 +03:00
|
|
|
/* static */ bool nsContentSecurityManager::AllowInsecureRedirectToDataURI(
|
|
|
|
nsIChannel* aNewChannel) {
|
|
|
|
nsCOMPtr<nsILoadInfo> loadInfo = aNewChannel->GetLoadInfo();
|
|
|
|
if (!loadInfo) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
bool isDataURI =
|
|
|
|
(NS_SUCCEEDED(newURI->SchemeIs("data", &isDataURI)) && isDataURI);
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
NS_ConvertUTF8toUTF16 specUTF16(NS_UnescapeURL(dataSpec));
|
|
|
|
const char16_t* params[] = {specUTF16.get()};
|
|
|
|
nsContentUtils::ReportToConsole(
|
|
|
|
nsIScriptError::warningFlag, NS_LITERAL_CSTRING("DATA_URI_BLOCKED"), doc,
|
|
|
|
nsContentUtils::eSECURITY_PROPERTIES, "BlockSubresourceRedirectToData",
|
|
|
|
params, ArrayLength(params));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-04-06 01:27:02 +03:00
|
|
|
/* static */ nsresult nsContentSecurityManager::CheckFTPSubresourceLoad(
|
|
|
|
nsIChannel* aChannel) {
|
2018-05-02 14:32:08 +03:00
|
|
|
// We dissallow using FTP resources as a subresource almost 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.
|
2018-04-09 22:07:01 +03:00
|
|
|
if (!mozilla::net::nsIOService::BlockFTPSubresources()) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2018-03-26 22:05:08 +03:00
|
|
|
|
|
|
|
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
|
|
|
|
if (!loadInfo) {
|
2018-04-06 01:27:02 +03:00
|
|
|
return NS_OK;
|
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();
|
|
|
|
if (nsContentUtils::IsSystemPrincipal(triggeringPrincipal)) {
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
bool isFtpURI = (NS_SUCCEEDED(uri->SchemeIs("ftp", &isFtpURI)) && isFtpURI);
|
|
|
|
if (!isFtpURI) {
|
2018-04-06 01:27:02 +03:00
|
|
|
return NS_OK;
|
2018-03-26 22:05:08 +03:00
|
|
|
}
|
|
|
|
|
2018-05-02 14:32:08 +03:00
|
|
|
// Allow loading FTP subresources in FTP documents, like XML.
|
|
|
|
nsCOMPtr<nsIURI> triggeringURI;
|
|
|
|
triggeringPrincipal->GetURI(getter_AddRefs(triggeringURI));
|
|
|
|
if (triggeringURI && nsContentUtils::SchemeIs(triggeringURI, "ftp")) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
NS_ConvertUTF8toUTF16 specUTF16(NS_UnescapeURL(spec));
|
|
|
|
const char16_t* params[] = {specUTF16.get()};
|
|
|
|
|
|
|
|
nsContentUtils::ReportToConsole(
|
|
|
|
nsIScriptError::warningFlag, NS_LITERAL_CSTRING("FTP_URI_BLOCKED"), doc,
|
|
|
|
nsContentUtils::eSECURITY_PROPERTIES, "BlockSubresourceFTP", params,
|
|
|
|
ArrayLength(params));
|
|
|
|
|
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.
|
2015-07-20 05:12:11 +03:00
|
|
|
if (securityMode != nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS &&
|
|
|
|
securityMode != nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED &&
|
|
|
|
securityMode != nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS &&
|
|
|
|
securityMode != nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL &&
|
|
|
|
securityMode != nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS) {
|
|
|
|
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;
|
|
|
|
docShellTreeItem->GetRootTreeItem(getter_AddRefs(root));
|
|
|
|
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) {
|
2015-11-26 00:38:05 +03:00
|
|
|
// Bug 1228117: determine the correct security policy for DTD loads
|
|
|
|
if (aLoadInfo->GetExternalContentPolicyType() == nsIContentPolicy::TYPE_DTD) {
|
|
|
|
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
|
|
|
|
2015-09-15 04:59:35 +03:00
|
|
|
uint32_t flags = nsIScriptSecurityManager::STANDARD;
|
|
|
|
if (aLoadInfo->GetAllowChrome()) {
|
|
|
|
flags |= nsIScriptSecurityManager::ALLOW_CHROME;
|
|
|
|
}
|
2016-05-24 00:57:31 +03:00
|
|
|
if (aLoadInfo->GetDisallowScript()) {
|
|
|
|
flags |= nsIScriptSecurityManager::DISALLOW_SCRIPT;
|
|
|
|
}
|
2015-09-15 04:59:35 +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(
|
|
|
|
aLoadInfo->TriggeringPrincipal(), aURI, flags);
|
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
|
|
|
}
|
|
|
|
|
2015-12-07 02:33:15 +03:00
|
|
|
NS_ENSURE_FALSE(NS_HasBeenCrossOrigin(aChannel, true), 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.
|
|
|
|
// For example, allow user stylesheets to load XBL from external files
|
|
|
|
// without requiring CORS.
|
|
|
|
if (nsContentUtils::IsSystemPrincipal(aLoadInfo->TriggeringPrincipal())) {
|
|
|
|
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);
|
|
|
|
|
|
|
|
if (contentPolicyType == nsIContentPolicy::TYPE_DOCUMENT ||
|
|
|
|
contentPolicyType == nsIContentPolicy::TYPE_SUBDOCUMENT) {
|
|
|
|
// TYPE_DOCUMENT and TYPE_SUBDOCUMENT loads might potentially
|
|
|
|
// be wyciwyg:// channels. Let's fix up the URI so we can
|
|
|
|
// perform proper security checks.
|
2019-01-29 11:03:06 +03:00
|
|
|
nsCOMPtr<nsIURIFixup> urifixup(do_GetService(NS_URIFIXUP_CONTRACTID, &rv));
|
|
|
|
if (NS_SUCCEEDED(rv) && urifixup) {
|
2017-01-03 22:59:30 +03:00
|
|
|
nsCOMPtr<nsIURI> fixedURI;
|
|
|
|
rv = urifixup->CreateExposableURI(uri, getter_AddRefs(fixedURI));
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
uri = fixedURI;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-06-29 13:59:45 +03:00
|
|
|
|
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: {
|
|
|
|
mimeTypeGuess = NS_LITERAL_CSTRING("application/javascript");
|
|
|
|
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: {
|
|
|
|
mimeTypeGuess = NS_LITERAL_CSTRING("text/css");
|
|
|
|
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: {
|
|
|
|
mimeTypeGuess = NS_LITERAL_CSTRING("text/html");
|
|
|
|
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-09-15 04:59:35 +03:00
|
|
|
case nsIContentPolicy::TYPE_XBL: {
|
|
|
|
mimeTypeGuess = EmptyCString();
|
|
|
|
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");
|
|
|
|
mimeTypeGuess = NS_LITERAL_CSTRING(TEXT_EVENT_STREAM);
|
|
|
|
}
|
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) {
|
|
|
|
mimeTypeGuess = NS_LITERAL_CSTRING("text/vtt");
|
|
|
|
} 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: {
|
|
|
|
mimeTypeGuess = NS_LITERAL_CSTRING("application/xml");
|
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: {
|
|
|
|
mimeTypeGuess = NS_LITERAL_CSTRING("application/manifest+json");
|
|
|
|
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)) {
|
|
|
|
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,
|
|
|
|
const nsAString& aPrincipalName) {
|
|
|
|
if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
|
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Debug,
|
|
|
|
(" %s: SystemPrincipal\n",
|
|
|
|
NS_ConvertUTF16toUTF8(aPrincipalName).get()));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (aPrincipal) {
|
|
|
|
if (aPrincipal->GetIsNullPrincipal()) {
|
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Debug,
|
|
|
|
(" %s: NullPrincipal\n",
|
|
|
|
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,
|
|
|
|
(" %s: %s\n", NS_ConvertUTF16toUTF8(aPrincipalName).get(),
|
|
|
|
origin.get()));
|
2018-09-28 16:06:29 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
nsCOMPtr<nsIURI> principalURI;
|
|
|
|
nsAutoCString principalSpec;
|
|
|
|
aPrincipal->GetURI(getter_AddRefs(principalURI));
|
|
|
|
if (principalURI) {
|
|
|
|
principalURI->GetSpec(principalSpec);
|
|
|
|
}
|
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Debug,
|
|
|
|
(" %s: %s\n", NS_ConvertUTF16toUTF8(aPrincipalName).get(),
|
|
|
|
principalSpec.get()));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Debug,
|
|
|
|
(" %s: nullptr\n", NS_ConvertUTF16toUTF8(aPrincipalName).get()));
|
|
|
|
}
|
|
|
|
|
|
|
|
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"},
|
|
|
|
{nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS,
|
|
|
|
"SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS"},
|
|
|
|
{nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED,
|
|
|
|
"SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED"},
|
|
|
|
{nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS,
|
|
|
|
"SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS"},
|
|
|
|
{nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
|
|
|
|
"SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL"},
|
|
|
|
{nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS,
|
|
|
|
"SEC_REQUIRE_CORS_DATA_INHERITS"},
|
|
|
|
{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_SANDBOXED, "SEC_SANDBOXED"},
|
|
|
|
{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
|
|
|
|
2018-09-28 16:06:29 +03:00
|
|
|
for (const DebugSecFlagType flag : secTypes) {
|
|
|
|
if (securityFlags & flag.secFlag) {
|
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Debug, (" %s,\n", flag.secTypeStr));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
static void DebugDoContentSecurityCheck(nsIChannel* aChannel,
|
|
|
|
nsILoadInfo* aLoadInfo) {
|
|
|
|
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Debug, ("doContentSecurityCheck {\n"));
|
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Debug,
|
|
|
|
(" channelURI: %s\n", channelSpec.get()));
|
|
|
|
|
|
|
|
// Log HTTP-specific things
|
|
|
|
if (httpChannel) {
|
|
|
|
nsresult rv;
|
|
|
|
rv = httpChannel->GetRequestMethod(channelMethod);
|
|
|
|
if (!NS_FAILED(rv)) {
|
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Debug,
|
|
|
|
(" HTTP Method: %s\n", channelMethod.get()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Log Principals
|
|
|
|
nsCOMPtr<nsIPrincipal> requestPrincipal = aLoadInfo->TriggeringPrincipal();
|
|
|
|
LogPrincipal(aLoadInfo->LoadingPrincipal(),
|
|
|
|
NS_LITERAL_STRING("loadingPrincipal"));
|
|
|
|
LogPrincipal(requestPrincipal, NS_LITERAL_STRING("triggeringPrincipal"));
|
|
|
|
LogPrincipal(aLoadInfo->PrincipalToInherit(),
|
|
|
|
NS_LITERAL_STRING("principalToInherit"));
|
|
|
|
|
|
|
|
// Log Redirect Chain
|
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Debug, (" RedirectChain:\n"));
|
|
|
|
for (nsIRedirectHistoryEntry* redirectHistoryEntry :
|
|
|
|
aLoadInfo->RedirectChain()) {
|
|
|
|
nsCOMPtr<nsIPrincipal> principal;
|
|
|
|
redirectHistoryEntry->GetPrincipal(getter_AddRefs(principal));
|
|
|
|
LogPrincipal(principal, NS_LITERAL_STRING("->"));
|
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Debug,
|
|
|
|
(" internalContentPolicyType: %d\n",
|
|
|
|
aLoadInfo->InternalContentPolicyType()));
|
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Debug,
|
|
|
|
(" externalContentPolicyType: %d\n",
|
|
|
|
aLoadInfo->GetExternalContentPolicyType()));
|
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Debug,
|
|
|
|
(" upgradeInsecureRequests: %s\n",
|
|
|
|
aLoadInfo->GetUpgradeInsecureRequests() ? "true" : "false"));
|
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Debug,
|
|
|
|
(" initalSecurityChecksDone: %s\n",
|
|
|
|
aLoadInfo->GetInitialSecurityCheckDone() ? "true" : "false"));
|
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Debug,
|
|
|
|
(" enforceSecurity: %s\n",
|
|
|
|
aLoadInfo->GetEnforceSecurity() ? "true" : "false"));
|
|
|
|
|
|
|
|
// Log CSPrequestPrincipal
|
|
|
|
nsCOMPtr<nsIContentSecurityPolicy> csp;
|
|
|
|
requestPrincipal->GetCsp(getter_AddRefs(csp));
|
|
|
|
if (csp) {
|
|
|
|
nsAutoString parsedPolicyStr;
|
|
|
|
uint32_t count = 0;
|
|
|
|
csp->GetPolicyCount(&count);
|
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Debug, (" CSP (%d): ", count));
|
|
|
|
for (uint32_t i = 0; i < count; ++i) {
|
|
|
|
csp->GetPolicyString(i, parsedPolicyStr);
|
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Debug,
|
|
|
|
(" %s\n", NS_ConvertUTF16toUTF8(parsedPolicyStr).get()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Security Flags
|
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Debug, (" securityFlags: "));
|
|
|
|
LogSecurityFlags(aLoadInfo->GetSecurityFlags());
|
|
|
|
MOZ_LOG(sCSMLog, LogLevel::Debug, ("}\n\n"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
* The streamListener that is passed to channel->AsyncOpen2() that is now
|
|
|
|
* 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);
|
|
|
|
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
|
|
|
|
|
|
|
|
if (!loadInfo) {
|
|
|
|
MOZ_ASSERT(false,
|
|
|
|
"channel needs to have loadInfo to perform security checks");
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
|
|
|
|
2018-09-28 16:06:29 +03:00
|
|
|
if (MOZ_UNLIKELY(MOZ_LOG_TEST(sCSMLog, LogLevel::Debug))) {
|
|
|
|
DebugDoContentSecurityCheck(aChannel, loadInfo);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
nsresult rv = ValidateSecurityFlags(loadInfo);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
// since aChannel was openend using asyncOpen2() we have to make sure
|
|
|
|
// that redirects of that channel also get openend using asyncOpen2()
|
|
|
|
// please note that some implementations of ::AsyncOpen2 might already
|
|
|
|
// have set that flag to true (e.g. nsViewSourceChannel) in which case
|
|
|
|
// we just set the flag again.
|
2016-08-12 08:19:29 +03:00
|
|
|
loadInfo->SetEnforceSecurity(true);
|
2015-07-20 05:12:11 +03:00
|
|
|
|
2015-12-07 02:33:14 +03:00
|
|
|
if (loadInfo->GetSecurityMode() ==
|
|
|
|
nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS) {
|
|
|
|
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) {
|
|
|
|
nsCOMPtr<nsILoadInfo> loadInfo = aOldChannel->GetLoadInfo();
|
|
|
|
// Are we enforcing security using LoadInfo?
|
|
|
|
if (loadInfo && loadInfo->GetEnforceSecurity()) {
|
|
|
|
nsresult rv = CheckChannel(aNewChannel);
|
2018-04-06 01:27:02 +03:00
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
rv = CheckFTPSubresourceLoad(aNewChannel);
|
|
|
|
}
|
2015-12-07 02:33:14 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
aOldChannel->Cancel(rv);
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
nsresult rv = nsContentUtils::GetSecurityManager()->CheckLoadURIWithPrincipal(
|
|
|
|
oldPrincipal, newURI, flags);
|
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) {
|
|
|
|
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
|
|
|
|
MOZ_ASSERT(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);
|
|
|
|
|
2017-01-03 22:59:30 +03:00
|
|
|
nsContentPolicyType contentPolicyType =
|
|
|
|
loadInfo->GetExternalContentPolicyType();
|
|
|
|
|
|
|
|
if (contentPolicyType == nsIContentPolicy::TYPE_DOCUMENT ||
|
|
|
|
contentPolicyType == nsIContentPolicy::TYPE_SUBDOCUMENT) {
|
|
|
|
// TYPE_DOCUMENT and TYPE_SUBDOCUMENT loads might potentially
|
|
|
|
// be wyciwyg:// channels. Let's fix up the URI so we can
|
|
|
|
// perform proper security checks.
|
2019-01-29 11:03:06 +03:00
|
|
|
nsCOMPtr<nsIURIFixup> urifixup(do_GetService(NS_URIFIXUP_CONTRACTID, &rv));
|
|
|
|
if (NS_SUCCEEDED(rv) && urifixup) {
|
2017-01-03 22:59:30 +03:00
|
|
|
nsCOMPtr<nsIURI> fixedURI;
|
|
|
|
rv = urifixup->CreateExposableURI(uri, getter_AddRefs(fixedURI));
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
uri = fixedURI;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-07 02:33:15 +03:00
|
|
|
// 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);
|
2015-12-07 02:33:15 +03:00
|
|
|
nsIPrincipal* loadingPrincipal = loadInfo->LoadingPrincipal();
|
|
|
|
|
|
|
|
// It doesn't matter what we pass for the third, data-inherits, argument.
|
|
|
|
// Any protocol which inherits won't pay attention to cookies anyway.
|
|
|
|
rv = loadingPrincipal->CheckMayLoad(uri, false, false);
|
|
|
|
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
|
2015-12-07 02:33:14 +03:00
|
|
|
if (securityMode == nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS) {
|
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.
|
|
|
|
// For example, allow user stylesheets to load XBL from external files.
|
|
|
|
if (nsContentUtils::IsSystemPrincipal(loadInfo->TriggeringPrincipal()) &&
|
|
|
|
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
|
|
|
|
if ((securityMode == nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS) ||
|
|
|
|
(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
|
|
|
|
2015-09-15 04:59:35 +03:00
|
|
|
if ((securityMode == nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS) ||
|
|
|
|
(securityMode == nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_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
|
|
|
|
// cross origin requests. If the flag SEC_REQUIRE_CORS_DATA_INHERITS 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;
|
|
|
|
}
|
2015-11-06 22:10:17 +03:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2016-04-26 13:30:43 +03:00
|
|
|
nsContentSecurityManager::IsOriginPotentiallyTrustworthy(
|
|
|
|
nsIPrincipal* aPrincipal, bool* aIsTrustWorthy) {
|
2015-11-06 22:10:17 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-04-26 13:30:43 +03:00
|
|
|
NS_ENSURE_ARG_POINTER(aPrincipal);
|
2015-11-06 22:10:17 +03:00
|
|
|
NS_ENSURE_ARG_POINTER(aIsTrustWorthy);
|
|
|
|
|
2019-01-03 23:55:38 +03:00
|
|
|
if (aPrincipal->IsSystemPrincipal()) {
|
2016-04-26 13:30:43 +03:00
|
|
|
*aIsTrustWorthy = true;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The following implements:
|
|
|
|
// https://w3c.github.io/webappsec-secure-contexts/#is-origin-trustworthy
|
|
|
|
|
2015-11-06 22:10:17 +03:00
|
|
|
*aIsTrustWorthy = false;
|
2016-04-26 13:30:43 +03:00
|
|
|
|
|
|
|
if (aPrincipal->GetIsNullPrincipal()) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_ASSERT(aPrincipal->GetIsCodebasePrincipal(),
|
|
|
|
"Nobody is expected to call us with an nsIExpandedPrincipal");
|
|
|
|
|
|
|
|
nsCOMPtr<nsIURI> uri;
|
|
|
|
aPrincipal->GetURI(getter_AddRefs(uri));
|
|
|
|
|
2015-11-06 22:10:17 +03:00
|
|
|
nsAutoCString scheme;
|
2016-04-26 13:30:43 +03:00
|
|
|
nsresult rv = uri->GetScheme(scheme);
|
2015-11-20 01:22:57 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2015-11-06 22:10:17 +03:00
|
|
|
|
2016-04-26 13:30:43 +03:00
|
|
|
// Blobs are expected to inherit their principal so we don't expect to have
|
|
|
|
// a codebase principal with scheme 'blob' here. We can't assert that though
|
|
|
|
// since someone could mess with a non-blob URI to give it that scheme.
|
2016-09-01 08:01:16 +03:00
|
|
|
NS_WARNING_ASSERTION(!scheme.EqualsLiteral("blob"),
|
|
|
|
"IsOriginPotentiallyTrustworthy ignoring blob scheme");
|
2016-04-26 13:30:43 +03:00
|
|
|
|
2016-01-18 17:54:18 +03:00
|
|
|
// According to the specification, the user agent may choose to extend the
|
|
|
|
// trust to other, vendor-specific URL schemes. We use this for "resource:",
|
|
|
|
// which is technically a substituting protocol handler that is not limited to
|
|
|
|
// local resource mapping, but in practice is never mapped remotely as this
|
|
|
|
// would violate assumptions a lot of code makes.
|
Bug 1328695 - Use protocol flags to determine if a URI is potentially trustworthy r=ckerschb, r=dveditz, r=mcmanus, r=bz
Before this change, the trusted URI schemes, based on a string whitelist, were:
https, file, resource, app, moz-extension and wss.
This change removes "app" from the list (since we don't implement it),
and adds "about" to the list (because we control the delivery of that).
2018-05-31 08:51:42 +03:00
|
|
|
// We use nsIProtocolHandler flags to determine which protocols we consider a
|
|
|
|
// priori authenticated.
|
|
|
|
bool aPrioriAuthenticated = false;
|
|
|
|
if (NS_FAILED(NS_URIChainHasFlags(
|
|
|
|
uri, nsIProtocolHandler::URI_IS_POTENTIALLY_TRUSTWORTHY,
|
|
|
|
&aPrioriAuthenticated))) {
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aPrioriAuthenticated) {
|
2015-11-06 22:10:17 +03:00
|
|
|
*aIsTrustWorthy = true;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsAutoCString host;
|
2016-04-26 13:30:43 +03:00
|
|
|
rv = uri->GetHost(host);
|
2015-11-20 01:22:57 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2015-11-06 22:10:17 +03:00
|
|
|
|
2017-09-06 11:13:45 +03:00
|
|
|
if (host.EqualsLiteral("127.0.0.1") || host.EqualsLiteral("localhost") ||
|
|
|
|
host.EqualsLiteral("::1")) {
|
2015-11-06 22:10:17 +03:00
|
|
|
*aIsTrustWorthy = true;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2016-10-10 18:32:24 +03:00
|
|
|
|
|
|
|
// If a host is not considered secure according to the default algorithm, then
|
|
|
|
// check to see if it has been whitelisted by the user. We only apply this
|
|
|
|
// whitelist for network resources, i.e., those with scheme "http" or "ws".
|
|
|
|
// The pref should contain a comma-separated list of hostnames.
|
|
|
|
if (scheme.EqualsLiteral("http") || scheme.EqualsLiteral("ws")) {
|
2017-07-31 07:28:48 +03:00
|
|
|
nsAutoCString whitelist;
|
|
|
|
nsresult rv =
|
|
|
|
Preferences::GetCString("dom.securecontext.whitelist", whitelist);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
2016-10-10 18:32:24 +03:00
|
|
|
nsCCharSeparatedTokenizer tokenizer(whitelist, ',');
|
|
|
|
while (tokenizer.hasMoreTokens()) {
|
2017-06-20 12:19:52 +03:00
|
|
|
const nsACString& allowedHost = tokenizer.nextToken();
|
2016-10-10 18:32:24 +03:00
|
|
|
if (host.Equals(allowedHost)) {
|
|
|
|
*aIsTrustWorthy = true;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-03-01 11:44:30 +03:00
|
|
|
// Maybe we have a .onion URL. Treat it as whitelisted as well if
|
|
|
|
// `dom.securecontext.whitelist_onions` is `true`.
|
|
|
|
if (nsMixedContentBlocker::IsPotentiallyTrustworthyOnion(uri)) {
|
|
|
|
*aIsTrustWorthy = true;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2016-10-10 18:32:24 +03:00
|
|
|
}
|
|
|
|
|
2015-11-06 22:10:17 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|