1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "nsContentSecurityManager.h"
9 #include "nsContentSecurityUtils.h"
10 #include "nsContentPolicyUtils.h"
12 #include "nsDataHandler.h"
13 #include "nsIChannel.h"
14 #include "nsIContentPolicy.h"
15 #include "nsIHttpChannelInternal.h"
17 #include "nsIStreamListener.h"
18 #include "nsILoadInfo.h"
19 #include "nsIOService.h"
20 #include "nsContentUtils.h"
21 #include "nsCORSListenerProxy.h"
22 #include "nsIParentChannel.h"
23 #include "nsIStreamListener.h"
24 #include "nsIRedirectHistoryEntry.h"
25 #include "nsNetUtil.h"
26 #include "nsReadableUtils.h"
27 #include "nsSandboxFlags.h"
28 #include "nsIXPConnect.h"
30 #include "mozilla/BasePrincipal.h"
31 #include "mozilla/ClearOnShutdown.h"
32 #include "mozilla/CmdLineAndEnvUtils.h"
33 #include "mozilla/dom/Element.h"
34 #include "mozilla/dom/nsMixedContentBlocker.h"
35 #include "mozilla/dom/BrowserChild.h"
36 #include "mozilla/dom/ContentChild.h"
37 #include "mozilla/dom/ContentParent.h"
38 #include "mozilla/dom/Document.h"
39 #include "mozilla/Components.h"
40 #include "mozilla/Logging.h"
41 #include "mozilla/Maybe.h"
42 #include "mozilla/Preferences.h"
43 #include "mozilla/StaticPrefs_dom.h"
44 #include "mozilla/StaticPrefs_security.h"
45 #include "mozilla/Telemetry.h"
46 #include "mozilla/TelemetryComms.h"
47 #include "xpcpublic.h"
48 #include "nsMimeTypes.h"
51 #include "js/RegExp.h"
53 using namespace mozilla
;
54 using namespace mozilla::dom
;
55 using namespace mozilla::Telemetry
;
57 NS_IMPL_ISUPPORTS(nsContentSecurityManager
, nsIContentSecurityManager
,
60 mozilla::LazyLogModule
sCSMLog("CSMLog");
62 // These first two are used for off-the-main-thread checks of
63 // general.config.filename
64 // (which can't be checked off-main-thread).
65 Atomic
<bool, mozilla::Relaxed
> sJSHacksChecked(false);
66 Atomic
<bool, mozilla::Relaxed
> sJSHacksPresent(false);
67 Atomic
<bool, mozilla::Relaxed
> sTelemetryEventEnabled(false);
70 bool nsContentSecurityManager::AllowTopLevelNavigationToDataURI(
71 nsIChannel
* aChannel
) {
72 // Let's block all toplevel document navigations to a data: URI.
73 // In all cases where the toplevel document is navigated to a
74 // data: URI the triggeringPrincipal is a contentPrincipal, or
75 // a NullPrincipal. In other cases, e.g. typing a data: URL into
76 // the URL-Bar, the triggeringPrincipal is a SystemPrincipal;
77 // we don't want to block those loads. Only exception, loads coming
78 // from an external applicaton (e.g. Thunderbird) don't load
79 // using a contentPrincipal, but we want to block those loads.
80 if (!StaticPrefs::security_data_uri_block_toplevel_data_uri_navigations()) {
83 nsCOMPtr
<nsILoadInfo
> loadInfo
= aChannel
->LoadInfo();
84 if (loadInfo
->GetExternalContentPolicyType() !=
85 ExtContentPolicy::TYPE_DOCUMENT
) {
88 if (loadInfo
->GetForceAllowDataURI()) {
89 // if the loadinfo explicitly allows the data URI navigation, let's allow it
94 nsresult rv
= NS_GetFinalChannelURI(aChannel
, getter_AddRefs(uri
));
95 NS_ENSURE_SUCCESS(rv
, true);
96 bool isDataURI
= uri
->SchemeIs("data");
102 rv
= uri
->GetSpec(spec
);
103 NS_ENSURE_SUCCESS(rv
, true);
104 nsAutoCString contentType
;
106 rv
= nsDataHandler::ParseURI(spec
, contentType
, nullptr, base64
, nullptr);
107 NS_ENSURE_SUCCESS(rv
, true);
109 // Allow data: images as long as they are not SVGs
110 if (StringBeginsWith(contentType
, "image/"_ns
) &&
111 !contentType
.EqualsLiteral("image/svg+xml")) {
114 // Allow all data: PDFs. or JSON documents
115 if (contentType
.EqualsLiteral(APPLICATION_JSON
) ||
116 contentType
.EqualsLiteral(TEXT_JSON
) ||
117 contentType
.EqualsLiteral(APPLICATION_PDF
)) {
120 // Redirecting to a toplevel data: URI is not allowed, hence we make
121 // sure the RedirectChain is empty.
122 if (!loadInfo
->GetLoadTriggeredFromExternal() &&
123 loadInfo
->TriggeringPrincipal()->IsSystemPrincipal() &&
124 loadInfo
->RedirectChain().IsEmpty()) {
127 nsAutoCString dataSpec
;
128 uri
->GetSpec(dataSpec
);
129 if (dataSpec
.Length() > 50) {
130 dataSpec
.Truncate(50);
131 dataSpec
.AppendLiteral("...");
133 nsCOMPtr
<nsISupports
> context
= loadInfo
->ContextForTopLevelLoad();
134 nsCOMPtr
<nsIBrowserChild
> browserChild
= do_QueryInterface(context
);
135 nsCOMPtr
<Document
> doc
;
137 doc
= static_cast<mozilla::dom::BrowserChild
*>(browserChild
.get())
138 ->GetTopLevelDocument();
140 AutoTArray
<nsString
, 1> params
;
141 CopyUTF8toUTF16(NS_UnescapeURL(dataSpec
), *params
.AppendElement());
142 nsContentUtils::ReportToConsole(nsIScriptError::warningFlag
,
143 "DATA_URI_BLOCKED"_ns
, doc
,
144 nsContentUtils::eSECURITY_PROPERTIES
,
145 "BlockTopLevelDataURINavigation", params
);
150 bool nsContentSecurityManager::AllowInsecureRedirectToDataURI(
151 nsIChannel
* aNewChannel
) {
152 nsCOMPtr
<nsILoadInfo
> loadInfo
= aNewChannel
->LoadInfo();
153 if (loadInfo
->GetExternalContentPolicyType() !=
154 ExtContentPolicy::TYPE_SCRIPT
) {
157 nsCOMPtr
<nsIURI
> newURI
;
158 nsresult rv
= NS_GetFinalChannelURI(aNewChannel
, getter_AddRefs(newURI
));
159 if (NS_FAILED(rv
) || !newURI
) {
162 bool isDataURI
= newURI
->SchemeIs("data");
167 // Web Extensions are exempt from that restriction and are allowed to redirect
168 // a channel to a data: URI. When a web extension redirects a channel, we set
169 // a flag on the loadInfo which allows us to identify such redirects here.
170 if (loadInfo
->GetAllowInsecureRedirectToDataURI()) {
174 nsAutoCString dataSpec
;
175 newURI
->GetSpec(dataSpec
);
176 if (dataSpec
.Length() > 50) {
177 dataSpec
.Truncate(50);
178 dataSpec
.AppendLiteral("...");
180 nsCOMPtr
<Document
> doc
;
181 nsINode
* node
= loadInfo
->LoadingNode();
183 doc
= node
->OwnerDoc();
185 AutoTArray
<nsString
, 1> params
;
186 CopyUTF8toUTF16(NS_UnescapeURL(dataSpec
), *params
.AppendElement());
187 nsContentUtils::ReportToConsole(nsIScriptError::warningFlag
,
188 "DATA_URI_BLOCKED"_ns
, doc
,
189 nsContentUtils::eSECURITY_PROPERTIES
,
190 "BlockSubresourceRedirectToData", params
);
195 nsresult
nsContentSecurityManager::CheckFTPSubresourceLoad(
196 nsIChannel
* aChannel
) {
197 // We dissallow using FTP resources as a subresource everywhere.
198 // The only valid way to use FTP resources is loading it as
199 // a top level document.
201 nsCOMPtr
<nsILoadInfo
> loadInfo
= aChannel
->LoadInfo();
202 ExtContentPolicyType type
= loadInfo
->GetExternalContentPolicyType();
204 // Allow top-level FTP documents and save-as download of FTP files on
206 if (type
== ExtContentPolicy::TYPE_DOCUMENT
||
207 type
== ExtContentPolicy::TYPE_SAVEAS_DOWNLOAD
) {
211 // Allow the system principal to load everything. This is meant to
212 // temporarily fix downloads and pdf.js.
213 nsIPrincipal
* triggeringPrincipal
= loadInfo
->TriggeringPrincipal();
214 if (triggeringPrincipal
->IsSystemPrincipal()) {
218 nsCOMPtr
<nsIURI
> uri
;
219 nsresult rv
= NS_GetFinalChannelURI(aChannel
, getter_AddRefs(uri
));
220 NS_ENSURE_SUCCESS(rv
, rv
);
225 bool isFtpURI
= uri
->SchemeIs("ftp");
230 nsCOMPtr
<Document
> doc
;
231 if (nsINode
* node
= loadInfo
->LoadingNode()) {
232 doc
= node
->OwnerDoc();
237 AutoTArray
<nsString
, 1> params
;
238 CopyUTF8toUTF16(NS_UnescapeURL(spec
), *params
.AppendElement());
240 nsContentUtils::ReportToConsole(
241 nsIScriptError::warningFlag
, "FTP_URI_BLOCKED"_ns
, doc
,
242 nsContentUtils::eSECURITY_PROPERTIES
, "BlockSubresourceFTP", params
);
244 return NS_ERROR_CONTENT_BLOCKED
;
247 static nsresult
ValidateSecurityFlags(nsILoadInfo
* aLoadInfo
) {
248 nsSecurityFlags securityMode
= aLoadInfo
->GetSecurityMode();
250 // We should never perform a security check on a loadInfo that uses the flag
251 // SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK, because that is only used for
252 // temporary loadInfos used for explicit nsIContentPolicy checks, but never be
253 // set as a security flag on an actual channel.
255 nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_INHERITS_SEC_CONTEXT
&&
256 securityMode
!= nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED
&&
258 nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT
&&
259 securityMode
!= nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL
&&
260 securityMode
!= nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT
) {
263 "need one securityflag from nsILoadInfo to perform security checks");
264 return NS_ERROR_FAILURE
;
267 // all good, found the right security flags
271 static already_AddRefed
<nsIPrincipal
> GetExtensionSandboxPrincipal(
272 nsILoadInfo
* aLoadInfo
) {
273 // An extension is allowed to load resources from itself when its pages are
274 // loaded into a sandboxed frame. Extension resources in a sandbox have
275 // a null principal and no access to extension APIs. See "sandbox" in
276 // MDN extension docs for more information.
277 if (!aLoadInfo
->TriggeringPrincipal()->GetIsNullPrincipal()) {
280 RefPtr
<Document
> doc
;
281 aLoadInfo
->GetLoadingDocument(getter_AddRefs(doc
));
282 if (!doc
|| !(doc
->GetSandboxFlags() & SANDBOXED_ORIGIN
)) {
286 // node principal is also a null principal here, so we need to
287 // create a principal using documentURI, which is the moz-extension
288 // uri for the page if this is an extension sandboxed page.
289 nsCOMPtr
<nsIPrincipal
> docPrincipal
= BasePrincipal::CreateContentPrincipal(
290 doc
->GetDocumentURI(), doc
->NodePrincipal()->OriginAttributesRef());
292 if (!BasePrincipal::Cast(docPrincipal
)->AddonPolicy()) {
295 return docPrincipal
.forget();
298 static bool IsImageLoadInEditorAppType(nsILoadInfo
* aLoadInfo
) {
299 // Editor apps get special treatment here, editors can load images
300 // from anywhere. This allows editor to insert images from file://
301 // into documents that are being edited.
302 nsContentPolicyType type
= aLoadInfo
->InternalContentPolicyType();
303 if (type
!= nsIContentPolicy::TYPE_INTERNAL_IMAGE
&&
304 type
!= nsIContentPolicy::TYPE_INTERNAL_IMAGE_PRELOAD
&&
305 type
!= nsIContentPolicy::TYPE_INTERNAL_IMAGE_FAVICON
&&
306 type
!= nsIContentPolicy::TYPE_IMAGESET
) {
310 auto appType
= nsIDocShell::APP_TYPE_UNKNOWN
;
311 nsINode
* node
= aLoadInfo
->LoadingNode();
315 Document
* doc
= node
->OwnerDoc();
320 nsCOMPtr
<nsIDocShellTreeItem
> docShellTreeItem
= doc
->GetDocShell();
321 if (!docShellTreeItem
) {
325 nsCOMPtr
<nsIDocShellTreeItem
> root
;
326 docShellTreeItem
->GetInProcessRootTreeItem(getter_AddRefs(root
));
327 nsCOMPtr
<nsIDocShell
> docShell(do_QueryInterface(root
));
329 appType
= docShell
->GetAppType();
332 return appType
== nsIDocShell::APP_TYPE_EDITOR
;
335 static nsresult
DoCheckLoadURIChecks(nsIURI
* aURI
, nsILoadInfo
* aLoadInfo
) {
336 // In practice, these DTDs are just used for localization, so applying the
337 // same principal check as Fluent.
338 if (aLoadInfo
->InternalContentPolicyType() ==
339 nsIContentPolicy::TYPE_INTERNAL_DTD
) {
340 RefPtr
<Document
> doc
;
341 aLoadInfo
->GetLoadingDocument(getter_AddRefs(doc
));
342 bool allowed
= false;
343 aLoadInfo
->TriggeringPrincipal()->IsL10nAllowed(
344 doc
? doc
->GetDocumentURI() : nullptr, &allowed
);
346 return allowed
? NS_OK
: NS_ERROR_DOM_BAD_URI
;
349 // This is used in order to allow a privileged DOMParser to parse documents
350 // that need to access localization DTDs. We just allow through
351 // TYPE_INTERNAL_FORCE_ALLOWED_DTD no matter what the triggering principal is.
352 if (aLoadInfo
->InternalContentPolicyType() ==
353 nsIContentPolicy::TYPE_INTERNAL_FORCE_ALLOWED_DTD
) {
357 if (IsImageLoadInEditorAppType(aLoadInfo
)) {
361 nsCOMPtr
<nsIPrincipal
> triggeringPrincipal
= aLoadInfo
->TriggeringPrincipal();
362 nsCOMPtr
<nsIPrincipal
> addonPrincipal
=
363 GetExtensionSandboxPrincipal(aLoadInfo
);
364 if (addonPrincipal
) {
365 // call CheckLoadURIWithPrincipal() as below to continue other checks, but
366 // with the addon principal.
367 triggeringPrincipal
= addonPrincipal
;
370 // Only call CheckLoadURIWithPrincipal() using the TriggeringPrincipal and not
371 // the LoadingPrincipal when SEC_ALLOW_CROSS_ORIGIN_* security flags are set,
372 // to allow, e.g. user stylesheets to load chrome:// URIs.
373 return nsContentUtils::GetSecurityManager()->CheckLoadURIWithPrincipal(
374 triggeringPrincipal
, aURI
, aLoadInfo
->CheckLoadURIFlags(),
375 aLoadInfo
->GetInnerWindowID());
378 static bool URIHasFlags(nsIURI
* aURI
, uint32_t aURIFlags
) {
380 nsresult rv
= NS_URIChainHasFlags(aURI
, aURIFlags
, &hasFlags
);
381 NS_ENSURE_SUCCESS(rv
, false);
386 static nsresult
DoSOPChecks(nsIURI
* aURI
, nsILoadInfo
* aLoadInfo
,
387 nsIChannel
* aChannel
) {
388 if (aLoadInfo
->GetAllowChrome() &&
389 (URIHasFlags(aURI
, nsIProtocolHandler::URI_IS_UI_RESOURCE
) ||
390 nsContentUtils::SchemeIs(aURI
, "moz-safe-about"))) {
391 // UI resources are allowed.
392 return DoCheckLoadURIChecks(aURI
, aLoadInfo
);
395 if (NS_HasBeenCrossOrigin(aChannel
, true)) {
396 NS_SetRequestBlockingReason(aLoadInfo
,
397 nsILoadInfo::BLOCKING_REASON_NOT_SAME_ORIGIN
);
398 return NS_ERROR_DOM_BAD_URI
;
404 static nsresult
DoCORSChecks(nsIChannel
* aChannel
, nsILoadInfo
* aLoadInfo
,
405 nsCOMPtr
<nsIStreamListener
>& aInAndOutListener
) {
406 MOZ_RELEASE_ASSERT(aInAndOutListener
,
407 "can not perform CORS checks without a listener");
409 // No need to set up CORS if TriggeringPrincipal is the SystemPrincipal.
410 if (aLoadInfo
->TriggeringPrincipal()->IsSystemPrincipal()) {
414 // We use the triggering principal here, rather than the loading principal
415 // to ensure that anonymous CORS content in the browser resources and in
416 // WebExtensions is allowed to load.
417 nsIPrincipal
* principal
= aLoadInfo
->TriggeringPrincipal();
418 RefPtr
<nsCORSListenerProxy
> corsListener
= new nsCORSListenerProxy(
419 aInAndOutListener
, principal
,
420 aLoadInfo
->GetCookiePolicy() == nsILoadInfo::SEC_COOKIES_INCLUDE
);
421 // XXX: @arg: DataURIHandling::Allow
422 // lets use DataURIHandling::Allow for now and then decide on callsite basis.
424 // http://mxr.mozilla.org/mozilla-central/source/dom/security/nsCORSListenerProxy.h#33
425 nsresult rv
= corsListener
->Init(aChannel
, DataURIHandling::Allow
);
426 NS_ENSURE_SUCCESS(rv
, rv
);
427 aInAndOutListener
= corsListener
;
431 static nsresult
DoContentSecurityChecks(nsIChannel
* aChannel
,
432 nsILoadInfo
* aLoadInfo
) {
433 ExtContentPolicyType contentPolicyType
=
434 aLoadInfo
->GetExternalContentPolicyType();
435 nsContentPolicyType internalContentPolicyType
=
436 aLoadInfo
->InternalContentPolicyType();
437 nsCString mimeTypeGuess
;
439 nsCOMPtr
<nsIURI
> uri
;
440 nsresult rv
= NS_GetFinalChannelURI(aChannel
, getter_AddRefs(uri
));
441 NS_ENSURE_SUCCESS(rv
, rv
);
443 switch (contentPolicyType
) {
444 case ExtContentPolicy::TYPE_OTHER
: {
445 mimeTypeGuess
.Truncate();
449 case ExtContentPolicy::TYPE_SCRIPT
: {
450 mimeTypeGuess
= "application/javascript"_ns
;
454 case ExtContentPolicy::TYPE_IMAGE
: {
455 mimeTypeGuess
.Truncate();
459 case ExtContentPolicy::TYPE_STYLESHEET
: {
460 mimeTypeGuess
= "text/css"_ns
;
464 case ExtContentPolicy::TYPE_OBJECT
: {
465 mimeTypeGuess
.Truncate();
469 case ExtContentPolicy::TYPE_DOCUMENT
: {
470 mimeTypeGuess
.Truncate();
474 case ExtContentPolicy::TYPE_SUBDOCUMENT
: {
475 mimeTypeGuess
= "text/html"_ns
;
479 case ExtContentPolicy::TYPE_PING
: {
480 mimeTypeGuess
.Truncate();
484 case ExtContentPolicy::TYPE_XMLHTTPREQUEST
: {
487 nsCOMPtr
<nsINode
> node
= aLoadInfo
->LoadingNode();
488 MOZ_ASSERT(!node
|| node
->NodeType() == nsINode::DOCUMENT_NODE
,
489 "type_xml requires requestingContext of type Document");
492 // We're checking for the external TYPE_XMLHTTPREQUEST here in case
493 // an addon creates a request with that type.
494 if (internalContentPolicyType
==
495 nsIContentPolicy::TYPE_INTERNAL_XMLHTTPREQUEST
||
496 internalContentPolicyType
== nsIContentPolicy::TYPE_XMLHTTPREQUEST
) {
497 mimeTypeGuess
.Truncate();
499 MOZ_ASSERT(internalContentPolicyType
==
500 nsIContentPolicy::TYPE_INTERNAL_EVENTSOURCE
,
501 "can not set mime type guess for unexpected internal type");
502 mimeTypeGuess
= nsLiteralCString(TEXT_EVENT_STREAM
);
507 case ExtContentPolicy::TYPE_OBJECT_SUBREQUEST
: {
508 mimeTypeGuess
.Truncate();
511 nsCOMPtr
<nsINode
> node
= aLoadInfo
->LoadingNode();
513 !node
|| node
->NodeType() == nsINode::ELEMENT_NODE
,
514 "type_subrequest requires requestingContext of type Element");
520 case ExtContentPolicy::TYPE_DTD
: {
521 mimeTypeGuess
.Truncate();
524 nsCOMPtr
<nsINode
> node
= aLoadInfo
->LoadingNode();
525 MOZ_ASSERT(!node
|| node
->NodeType() == nsINode::DOCUMENT_NODE
,
526 "type_dtd requires requestingContext of type Document");
532 case ExtContentPolicy::TYPE_FONT
:
533 case ExtContentPolicy::TYPE_UA_FONT
: {
534 mimeTypeGuess
.Truncate();
538 case ExtContentPolicy::TYPE_MEDIA
: {
539 if (internalContentPolicyType
== nsIContentPolicy::TYPE_INTERNAL_TRACK
) {
540 mimeTypeGuess
= "text/vtt"_ns
;
542 mimeTypeGuess
.Truncate();
546 nsCOMPtr
<nsINode
> node
= aLoadInfo
->LoadingNode();
547 MOZ_ASSERT(!node
|| node
->NodeType() == nsINode::ELEMENT_NODE
,
548 "type_media requires requestingContext of type Element");
554 case ExtContentPolicy::TYPE_WEBSOCKET
: {
555 // Websockets have to use the proxied URI:
556 // ws:// instead of http:// for CSP checks
557 nsCOMPtr
<nsIHttpChannelInternal
> httpChannelInternal
=
558 do_QueryInterface(aChannel
);
559 MOZ_ASSERT(httpChannelInternal
);
560 if (httpChannelInternal
) {
561 rv
= httpChannelInternal
->GetProxyURI(getter_AddRefs(uri
));
562 MOZ_ASSERT(NS_SUCCEEDED(rv
));
564 mimeTypeGuess
.Truncate();
568 case ExtContentPolicy::TYPE_CSP_REPORT
: {
569 mimeTypeGuess
.Truncate();
573 case ExtContentPolicy::TYPE_XSLT
: {
574 mimeTypeGuess
= "application/xml"_ns
;
577 nsCOMPtr
<nsINode
> node
= aLoadInfo
->LoadingNode();
578 MOZ_ASSERT(!node
|| node
->NodeType() == nsINode::DOCUMENT_NODE
,
579 "type_xslt requires requestingContext of type Document");
585 case ExtContentPolicy::TYPE_BEACON
: {
586 mimeTypeGuess
.Truncate();
589 nsCOMPtr
<nsINode
> node
= aLoadInfo
->LoadingNode();
590 MOZ_ASSERT(!node
|| node
->NodeType() == nsINode::DOCUMENT_NODE
,
591 "type_beacon requires requestingContext of type Document");
597 case ExtContentPolicy::TYPE_FETCH
: {
598 mimeTypeGuess
.Truncate();
602 case ExtContentPolicy::TYPE_IMAGESET
: {
603 mimeTypeGuess
.Truncate();
607 case ExtContentPolicy::TYPE_WEB_MANIFEST
: {
608 mimeTypeGuess
= "application/manifest+json"_ns
;
612 case ExtContentPolicy::TYPE_SAVEAS_DOWNLOAD
: {
613 mimeTypeGuess
.Truncate();
617 case ExtContentPolicy::TYPE_SPECULATIVE
: {
618 mimeTypeGuess
.Truncate();
622 case ExtContentPolicy::TYPE_PROXIED_WEBRTC_MEDIA
: {
623 mimeTypeGuess
.Truncate();
627 case ExtContentPolicy::TYPE_INVALID
:
629 "can not perform security check without a valid contentType");
630 // Do not add default: so that compilers can catch the missing case.
633 int16_t shouldLoad
= nsIContentPolicy::ACCEPT
;
634 rv
= NS_CheckContentLoadPolicy(uri
, aLoadInfo
, mimeTypeGuess
, &shouldLoad
,
635 nsContentUtils::GetContentPolicy());
637 if (NS_FAILED(rv
) || NS_CP_REJECTED(shouldLoad
)) {
638 NS_SetRequestBlockingReasonIfNull(
639 aLoadInfo
, nsILoadInfo::BLOCKING_REASON_CONTENT_POLICY_GENERAL
);
641 if (NS_SUCCEEDED(rv
) &&
642 (contentPolicyType
== ExtContentPolicy::TYPE_DOCUMENT
||
643 contentPolicyType
== ExtContentPolicy::TYPE_SUBDOCUMENT
)) {
644 if (shouldLoad
== nsIContentPolicy::REJECT_TYPE
) {
645 // for docshell loads we might have to return SHOW_ALT.
646 return NS_ERROR_CONTENT_BLOCKED_SHOW_ALT
;
648 if (shouldLoad
== nsIContentPolicy::REJECT_POLICY
) {
649 return NS_ERROR_BLOCKED_BY_POLICY
;
652 return NS_ERROR_CONTENT_BLOCKED
;
658 static void LogHTTPSOnlyInfo(nsILoadInfo
* aLoadInfo
) {
659 MOZ_LOG(sCSMLog
, LogLevel::Verbose
, (" - https-only/https-first flags:"));
660 uint32_t httpsOnlyStatus
= aLoadInfo
->GetHttpsOnlyStatus();
662 if (httpsOnlyStatus
& nsILoadInfo::HTTPS_ONLY_UNINITIALIZED
) {
663 MOZ_LOG(sCSMLog
, LogLevel::Verbose
, (" - HTTPS_ONLY_UNINITIALIZED"));
665 if (httpsOnlyStatus
&
666 nsILoadInfo::HTTPS_ONLY_UPGRADED_LISTENER_NOT_REGISTERED
) {
667 MOZ_LOG(sCSMLog
, LogLevel::Verbose
,
668 (" - HTTPS_ONLY_UPGRADED_LISTENER_NOT_REGISTERED"));
670 if (httpsOnlyStatus
& nsILoadInfo::HTTPS_ONLY_UPGRADED_LISTENER_REGISTERED
) {
671 MOZ_LOG(sCSMLog
, LogLevel::Verbose
,
672 (" - HTTPS_ONLY_UPGRADED_LISTENER_REGISTERED"));
674 if (httpsOnlyStatus
& nsILoadInfo::HTTPS_ONLY_EXEMPT
) {
675 MOZ_LOG(sCSMLog
, LogLevel::Verbose
, (" - HTTPS_ONLY_EXEMPT"));
677 if (httpsOnlyStatus
& nsILoadInfo::HTTPS_ONLY_TOP_LEVEL_LOAD_IN_PROGRESS
) {
678 MOZ_LOG(sCSMLog
, LogLevel::Verbose
,
679 (" - HTTPS_ONLY_TOP_LEVEL_LOAD_IN_PROGRESS"));
681 if (httpsOnlyStatus
& nsILoadInfo::HTTPS_ONLY_DO_NOT_LOG_TO_CONSOLE
) {
682 MOZ_LOG(sCSMLog
, LogLevel::Verbose
,
683 (" - HTTPS_ONLY_DO_NOT_LOG_TO_CONSOLE"));
685 if (httpsOnlyStatus
& nsILoadInfo::HTTPS_ONLY_UPGRADED_HTTPS_FIRST
) {
686 MOZ_LOG(sCSMLog
, LogLevel::Verbose
,
687 (" - HTTPS_ONLY_UPGRADED_HTTPS_FIRST"));
691 static void LogPrincipal(nsIPrincipal
* aPrincipal
,
692 const nsAString
& aPrincipalName
,
693 const uint8_t& aNestingLevel
) {
694 nsPrintfCString
aIndentationString("%*s", aNestingLevel
* 2, "");
696 if (aPrincipal
&& aPrincipal
->IsSystemPrincipal()) {
697 MOZ_LOG(sCSMLog
, LogLevel::Debug
,
698 ("%s%s: SystemPrincipal\n", aIndentationString
.get(),
699 NS_ConvertUTF16toUTF8(aPrincipalName
).get()));
703 if (aPrincipal
->GetIsNullPrincipal()) {
704 MOZ_LOG(sCSMLog
, LogLevel::Debug
,
705 ("%s%s: NullPrincipal\n", aIndentationString
.get(),
706 NS_ConvertUTF16toUTF8(aPrincipalName
).get()));
709 if (aPrincipal
->GetIsExpandedPrincipal()) {
710 nsCOMPtr
<nsIExpandedPrincipal
> expanded(do_QueryInterface(aPrincipal
));
711 nsAutoCString origin
;
712 origin
.AssignLiteral("[Expanded Principal [");
714 StringJoinAppend(origin
, ", "_ns
, expanded
->AllowList(),
715 [](nsACString
& dest
, nsIPrincipal
* principal
) {
716 nsAutoCString subOrigin
;
717 DebugOnly
<nsresult
> rv
=
718 principal
->GetOrigin(subOrigin
);
719 MOZ_ASSERT(NS_SUCCEEDED(rv
));
720 dest
.Append(subOrigin
);
723 origin
.AppendLiteral("]]");
725 MOZ_LOG(sCSMLog
, LogLevel::Debug
,
726 ("%s%s: %s\n", aIndentationString
.get(),
727 NS_ConvertUTF16toUTF8(aPrincipalName
).get(), origin
.get()));
730 nsAutoCString principalSpec
;
731 aPrincipal
->GetAsciiSpec(principalSpec
);
732 MOZ_LOG(sCSMLog
, LogLevel::Debug
,
733 ("%s%s: %s\n", aIndentationString
.get(),
734 NS_ConvertUTF16toUTF8(aPrincipalName
).get(), principalSpec
.get()));
737 MOZ_LOG(sCSMLog
, LogLevel::Debug
,
738 ("%s%s: nullptr\n", aIndentationString
.get(),
739 NS_ConvertUTF16toUTF8(aPrincipalName
).get()));
742 static void LogSecurityFlags(nsSecurityFlags securityFlags
) {
743 struct DebugSecFlagType
{
744 unsigned long secFlag
;
745 char secTypeStr
[128];
747 static const DebugSecFlagType secTypes
[] = {
748 {nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK
,
749 "SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK"},
750 {nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_INHERITS_SEC_CONTEXT
,
751 "SEC_REQUIRE_SAME_ORIGIN_INHERITS_SEC_CONTEXT"},
752 {nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED
,
753 "SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED"},
754 {nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT
,
755 "SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT"},
756 {nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL
,
757 "SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL"},
758 {nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT
,
759 "SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT"},
760 {nsILoadInfo::SEC_COOKIES_DEFAULT
, "SEC_COOKIES_DEFAULT"},
761 {nsILoadInfo::SEC_COOKIES_INCLUDE
, "SEC_COOKIES_INCLUDE"},
762 {nsILoadInfo::SEC_COOKIES_SAME_ORIGIN
, "SEC_COOKIES_SAME_ORIGIN"},
763 {nsILoadInfo::SEC_COOKIES_OMIT
, "SEC_COOKIES_OMIT"},
764 {nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL
, "SEC_FORCE_INHERIT_PRINCIPAL"},
765 {nsILoadInfo::SEC_ABOUT_BLANK_INHERITS
, "SEC_ABOUT_BLANK_INHERITS"},
766 {nsILoadInfo::SEC_ALLOW_CHROME
, "SEC_ALLOW_CHROME"},
767 {nsILoadInfo::SEC_DISALLOW_SCRIPT
, "SEC_DISALLOW_SCRIPT"},
768 {nsILoadInfo::SEC_DONT_FOLLOW_REDIRECTS
, "SEC_DONT_FOLLOW_REDIRECTS"},
769 {nsILoadInfo::SEC_LOAD_ERROR_PAGE
, "SEC_LOAD_ERROR_PAGE"},
770 {nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL_OVERRULE_OWNER
,
771 "SEC_FORCE_INHERIT_PRINCIPAL_OVERRULE_OWNER"}};
773 for (const DebugSecFlagType
& flag
: secTypes
) {
774 if (securityFlags
& flag
.secFlag
) {
775 // the logging level should be in sync with the logging level in
776 // DebugDoContentSecurityCheck()
777 MOZ_LOG(sCSMLog
, LogLevel::Verbose
, (" - %s\n", flag
.secTypeStr
));
781 static void DebugDoContentSecurityCheck(nsIChannel
* aChannel
,
782 nsILoadInfo
* aLoadInfo
) {
783 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(aChannel
));
785 MOZ_LOG(sCSMLog
, LogLevel::Debug
, ("\n#DebugDoContentSecurityCheck Begin\n"));
787 // we only log http channels, unless loglevel is 5.
788 if (httpChannel
|| MOZ_LOG_TEST(sCSMLog
, LogLevel::Verbose
)) {
789 nsCOMPtr
<nsIURI
> channelURI
;
790 nsAutoCString channelSpec
;
791 nsAutoCString channelMethod
;
792 NS_GetFinalChannelURI(aChannel
, getter_AddRefs(channelURI
));
794 channelURI
->GetSpec(channelSpec
);
797 MOZ_LOG(sCSMLog
, LogLevel::Verbose
, ("doContentSecurityCheck:\n"));
799 MOZ_LOG(sCSMLog
, LogLevel::Verbose
,
800 (" - channelURI: %s\n", channelSpec
.get()));
802 // Log HTTP-specific things
805 rv
= httpChannel
->GetRequestMethod(channelMethod
);
806 if (!NS_FAILED(rv
)) {
807 MOZ_LOG(sCSMLog
, LogLevel::Verbose
,
808 (" - httpMethod: %s\n", channelMethod
.get()));
813 nsCOMPtr
<nsIPrincipal
> requestPrincipal
= aLoadInfo
->TriggeringPrincipal();
814 LogPrincipal(aLoadInfo
->GetLoadingPrincipal(), u
"- loadingPrincipal"_ns
, 1);
815 LogPrincipal(requestPrincipal
, u
"- triggeringPrincipal"_ns
, 1);
816 LogPrincipal(aLoadInfo
->PrincipalToInherit(), u
"- principalToInherit"_ns
,
819 // Log Redirect Chain
820 MOZ_LOG(sCSMLog
, LogLevel::Verbose
, (" - redirectChain:\n"));
821 for (nsIRedirectHistoryEntry
* redirectHistoryEntry
:
822 aLoadInfo
->RedirectChain()) {
823 nsCOMPtr
<nsIPrincipal
> principal
;
824 redirectHistoryEntry
->GetPrincipal(getter_AddRefs(principal
));
825 LogPrincipal(principal
, u
"-"_ns
, 2);
828 MOZ_LOG(sCSMLog
, LogLevel::Verbose
,
829 (" - internalContentPolicyType: %s\n",
830 NS_CP_ContentTypeName(aLoadInfo
->InternalContentPolicyType())));
831 MOZ_LOG(sCSMLog
, LogLevel::Verbose
,
832 (" - externalContentPolicyType: %s\n",
833 NS_CP_ContentTypeName(aLoadInfo
->GetExternalContentPolicyType())));
834 MOZ_LOG(sCSMLog
, LogLevel::Verbose
,
835 (" - upgradeInsecureRequests: %s\n",
836 aLoadInfo
->GetUpgradeInsecureRequests() ? "true" : "false"));
837 MOZ_LOG(sCSMLog
, LogLevel::Verbose
,
838 (" - initialSecurityChecksDone: %s\n",
839 aLoadInfo
->GetInitialSecurityCheckDone() ? "true" : "false"));
840 MOZ_LOG(sCSMLog
, LogLevel::Verbose
,
841 (" - allowDeprecatedSystemRequests: %s\n",
842 aLoadInfo
->GetAllowDeprecatedSystemRequests() ? "true" : "false"));
844 // Log CSPrequestPrincipal
845 nsCOMPtr
<nsIContentSecurityPolicy
> csp
= aLoadInfo
->GetCsp();
846 MOZ_LOG(sCSMLog
, LogLevel::Debug
, (" - CSP:"));
848 nsAutoString parsedPolicyStr
;
850 csp
->GetPolicyCount(&count
);
851 for (uint32_t i
= 0; i
< count
; ++i
) {
852 csp
->GetPolicyString(i
, parsedPolicyStr
);
853 // we need to add quotation marks, as otherwise yaml parsers may fail
854 // with CSP directives
855 // no need to escape quote marks in the parsed policy string, as URLs in
856 // there are already encoded
858 sCSMLog
, LogLevel::Debug
,
859 (" - \"%s\"\n", NS_ConvertUTF16toUTF8(parsedPolicyStr
).get()));
864 MOZ_LOG(sCSMLog
, LogLevel::Verbose
, (" - securityFlags:"));
865 LogSecurityFlags(aLoadInfo
->GetSecurityFlags());
866 LogHTTPSOnlyInfo(aLoadInfo
);
867 MOZ_LOG(sCSMLog
, LogLevel::Debug
, ("\n#DebugDoContentSecurityCheck End\n"));
872 void nsContentSecurityManager::MeasureUnexpectedPrivilegedLoads(
873 nsILoadInfo
* aLoadInfo
, nsIURI
* aFinalURI
, const nsACString
& aRemoteType
) {
874 if (!StaticPrefs::dom_security_unexpected_system_load_telemetry_enabled()) {
877 nsContentSecurityUtils::DetectJsHacks();
878 if (MOZ_UNLIKELY(sJSHacksPresent
)) {
882 ExtContentPolicyType contentPolicyType
=
883 aLoadInfo
->GetExternalContentPolicyType();
884 // restricting reported types to script, styles and documents
885 // to be continued in follow-ups of bug 1697163.
886 if (contentPolicyType
!= ExtContentPolicyType::TYPE_SCRIPT
&&
887 contentPolicyType
!= ExtContentPolicyType::TYPE_STYLESHEET
&&
888 contentPolicyType
!= ExtContentPolicyType::TYPE_DOCUMENT
) {
892 // Gather redirected schemes in string
893 nsAutoCString loggedRedirects
;
894 const nsTArray
<nsCOMPtr
<nsIRedirectHistoryEntry
>>& redirects
=
895 aLoadInfo
->RedirectChain();
896 if (!redirects
.IsEmpty()) {
897 nsCOMPtr
<nsIRedirectHistoryEntry
> end
= redirects
.LastElement();
898 for (nsIRedirectHistoryEntry
* entry
: redirects
) {
899 nsCOMPtr
<nsIPrincipal
> principal
;
900 entry
->GetPrincipal(getter_AddRefs(principal
));
902 nsAutoCString scheme
;
903 principal
->GetScheme(scheme
);
904 loggedRedirects
.Append(scheme
);
906 loggedRedirects
.AppendLiteral(", ");
912 nsAutoCString uriString
;
914 aFinalURI
->GetAsciiSpec(uriString
);
916 uriString
.AssignLiteral("");
918 FilenameTypeAndDetails fileNameTypeAndDetails
=
919 nsContentSecurityUtils::FilenameToFilenameType(
920 NS_ConvertUTF8toUTF16(uriString
), true);
922 nsCString loggedFileDetails
= "unknown"_ns
;
923 if (fileNameTypeAndDetails
.second
.isSome()) {
924 loggedFileDetails
.Assign(
925 NS_ConvertUTF16toUTF8(fileNameTypeAndDetails
.second
.value()));
927 // sanitize remoteType because it may contain sensitive
928 // info, like URLs. e.g. `webIsolated=https://example.com`
929 nsAutoCString
loggedRemoteType(dom::RemoteTypePrefix(aRemoteType
));
930 nsAutoCString
loggedContentType(NS_CP_ContentTypeName(contentPolicyType
));
932 MOZ_LOG(sCSMLog
, LogLevel::Debug
, ("UnexpectedPrivilegedLoadTelemetry:\n"));
933 MOZ_LOG(sCSMLog
, LogLevel::Debug
,
934 ("- contentType: %s\n", loggedContentType
.get()));
935 MOZ_LOG(sCSMLog
, LogLevel::Debug
,
936 ("- URL (not to be reported): %s\n", uriString
.get()));
937 MOZ_LOG(sCSMLog
, LogLevel::Debug
,
938 ("- remoteType: %s\n", loggedRemoteType
.get()));
939 MOZ_LOG(sCSMLog
, LogLevel::Debug
,
940 ("- fileInfo: %s\n", fileNameTypeAndDetails
.first
.get()));
941 MOZ_LOG(sCSMLog
, LogLevel::Debug
,
942 ("- fileDetails: %s\n", loggedFileDetails
.get()));
943 MOZ_LOG(sCSMLog
, LogLevel::Debug
,
944 ("- redirects: %s\n\n", loggedRedirects
.get()));
947 auto extra
= Some
<nsTArray
<EventExtraEntry
>>(
948 {EventExtraEntry
{"contenttype"_ns
, loggedContentType
},
949 EventExtraEntry
{"remotetype"_ns
, loggedRemoteType
},
950 EventExtraEntry
{"filedetails"_ns
, loggedFileDetails
},
951 EventExtraEntry
{"redirects"_ns
, loggedRedirects
}});
953 if (!sTelemetryEventEnabled
.exchange(true)) {
954 Telemetry::SetEventRecordingEnabled("security"_ns
, true);
957 Telemetry::EventID eventType
=
958 Telemetry::EventID::Security_Unexpectedload_Systemprincipal
;
959 Telemetry::RecordEvent(eventType
, mozilla::Some(fileNameTypeAndDetails
.first
),
964 nsresult
nsContentSecurityManager::CheckAllowLoadInSystemPrivilegedContext(
965 nsIChannel
* aChannel
) {
966 nsCOMPtr
<nsILoadInfo
> loadInfo
= aChannel
->LoadInfo();
968 // loads with the allow flag are waived through
969 // until refactored (e.g., Shavar, OCSP)
970 if (loadInfo
->GetAllowDeprecatedSystemRequests()) {
973 ExtContentPolicyType contentPolicyType
=
974 loadInfo
->GetExternalContentPolicyType();
976 // For now, let's not inspect top-level document loads
977 if (contentPolicyType
== ExtContentPolicy::TYPE_DOCUMENT
) {
981 // We mostly care about the triggeringPrincipal,
982 // unless this is a TYPE_DOCUMENT request, which has none.
983 nsCOMPtr
<nsIPrincipal
> inspectedPrincipal
;
984 if (contentPolicyType
!= ExtContentPolicy::TYPE_DOCUMENT
) {
985 inspectedPrincipal
= loadInfo
->GetLoadingPrincipal();
987 inspectedPrincipal
= loadInfo
->TriggeringPrincipal();
990 // Check if we are actually dealing with a SystemPrincipal request
991 if (!inspectedPrincipal
|| !inspectedPrincipal
->IsSystemPrincipal()) {
995 // allowing some fetches due to their lowered risk
996 // i.e., data & downloads fetches do limited parsing, no rendering
997 // remote images are too widely used (favicons, about:addons etc.)
998 if ((contentPolicyType
== ExtContentPolicy::TYPE_FETCH
) ||
999 (contentPolicyType
== ExtContentPolicy::TYPE_XMLHTTPREQUEST
) ||
1000 (contentPolicyType
== ExtContentPolicy::TYPE_WEBSOCKET
) ||
1001 (contentPolicyType
== ExtContentPolicy::TYPE_SAVEAS_DOWNLOAD
) ||
1002 (contentPolicyType
== ExtContentPolicy::TYPE_IMAGE
)) {
1006 // Allow the user interface (e.g., schemes like chrome, resource)
1007 nsCOMPtr
<nsIURI
> finalURI
;
1008 NS_GetFinalChannelURI(aChannel
, getter_AddRefs(finalURI
));
1009 bool isUiResource
= false;
1010 if (NS_SUCCEEDED(NS_URIChainHasFlags(
1011 finalURI
, nsIProtocolHandler::URI_IS_UI_RESOURCE
, &isUiResource
)) &&
1015 // For about: and extension-based URIs, which don't get
1016 // URI_IS_UI_RESOURCE, first remove layers of view-source:, if present.
1017 while (finalURI
&& finalURI
->SchemeIs("view-source")) {
1018 nsCOMPtr
<nsINestedURI
> nested
= do_QueryInterface(finalURI
);
1020 nested
->GetInnerURI(getter_AddRefs(finalURI
));
1024 nsAutoCString remoteType
;
1025 if (XRE_IsParentProcess()) {
1026 nsCOMPtr
<nsIParentChannel
> parentChannel
;
1027 NS_QueryNotificationCallbacks(aChannel
, parentChannel
);
1028 if (parentChannel
) {
1029 parentChannel
->GetRemoteType(remoteType
);
1033 mozilla::dom::ContentChild::GetSingleton()->GetRemoteType());
1036 // This is our escape hatch, if things break in release.
1037 // We expect to remove the pref in bug 1638770
1038 bool cancelNonLocalSystemPrincipal
= StaticPrefs::
1039 security_cancel_non_local_loads_triggered_by_systemprincipal();
1041 // GetInnerURI can return null for malformed nested URIs like moz-icon:trash
1043 MeasureUnexpectedPrivilegedLoads(loadInfo
, finalURI
, remoteType
);
1044 if (cancelNonLocalSystemPrincipal
) {
1045 aChannel
->Cancel(NS_ERROR_CONTENT_BLOCKED
);
1046 return NS_ERROR_CONTENT_BLOCKED
;
1049 // loads of userContent.css during startup and tests that show up as file:
1050 if (finalURI
->SchemeIs("file")) {
1051 if ((contentPolicyType
== ExtContentPolicy::TYPE_STYLESHEET
) ||
1052 (contentPolicyType
== ExtContentPolicy::TYPE_OTHER
)) {
1056 // (1)loads from within omni.ja and system add-ons use jar:
1057 // this is safe to allow, because we do not support remote jar.
1058 // (2) about: resources are always allowed: they are part of the build.
1059 // (3) extensions are signed or the user has made bad decisions.
1060 if (finalURI
->SchemeIs("jar") || finalURI
->SchemeIs("about") ||
1061 finalURI
->SchemeIs("moz-extension")) {
1064 // Telemetry for unexpected privileged loads.
1065 // pref check & data sanitization happens in the called function
1066 MeasureUnexpectedPrivilegedLoads(loadInfo
, finalURI
, remoteType
);
1068 // Relaxing restrictions for our test suites:
1069 // (1) AreNonLocalConnectionsDisabled() disables network, so http://mochitest
1070 // is actually local and allowed. (2) The marionette test framework uses
1071 // injections and data URLs to execute scripts, checking for the environment
1072 // variable breaks the attack but not the tests.
1073 if (xpc::AreNonLocalConnectionsDisabled() ||
1074 mozilla::EnvHasValue("MOZ_MARIONETTE")) {
1075 bool disallowSystemPrincipalRemoteDocuments
= Preferences::GetBool(
1076 "security.disallow_non_local_systemprincipal_in_tests");
1077 if (disallowSystemPrincipalRemoteDocuments
) {
1078 // our own mochitest needs NS_ASSERTION instead of MOZ_ASSERT
1079 NS_ASSERTION(false, "SystemPrincipal must not load remote documents.");
1080 aChannel
->Cancel(NS_ERROR_CONTENT_BLOCKED
);
1081 return NS_ERROR_CONTENT_BLOCKED
;
1083 // but other mochitest are exempt from this
1087 nsAutoCString requestedURL
;
1088 finalURI
->GetAsciiSpec(requestedURL
);
1089 MOZ_LOG(sCSMLog
, LogLevel::Warning
,
1090 ("SystemPrincipal should not load remote resources. URL: %s, type %d",
1091 requestedURL
.get(), int(contentPolicyType
)));
1093 // The load types that we want to disallow, will extend over time and
1094 // prioritized by risk. The most risky/dangerous are load-types are documents,
1095 // subdocuments, scripts and styles in that order. The most dangerous URL
1096 // schemes to cover are HTTP, HTTPS, data, blob in that order. Meta bug
1097 // 1725112 will track upcoming restrictions
1098 if (contentPolicyType
== ExtContentPolicy::TYPE_SUBDOCUMENT
) {
1099 if (StaticPrefs::security_disallow_privileged_https_subdocuments_loads() &&
1100 (finalURI
->SchemeIs("http") || finalURI
->SchemeIs("https"))) {
1102 MOZ_CRASH("Disallowing SystemPrincipal load of subdocuments on HTTP(S).");
1104 aChannel
->Cancel(NS_ERROR_CONTENT_BLOCKED
);
1105 return NS_ERROR_CONTENT_BLOCKED
;
1107 if ((StaticPrefs::security_disallow_privileged_data_subdocuments_loads()) &&
1108 (finalURI
->SchemeIs("data"))) {
1111 "Disallowing SystemPrincipal load of subdocuments on data URL.");
1113 aChannel
->Cancel(NS_ERROR_CONTENT_BLOCKED
);
1114 return NS_ERROR_CONTENT_BLOCKED
;
1118 if (cancelNonLocalSystemPrincipal
) {
1119 MOZ_ASSERT(false, "SystemPrincipal must not load remote documents.");
1120 aChannel
->Cancel(NS_ERROR_CONTENT_BLOCKED
);
1121 return NS_ERROR_CONTENT_BLOCKED
;
1127 * Every protocol handler must set one of the five security flags
1128 * defined in nsIProtocolHandler - if not - deny the load.
1130 nsresult
nsContentSecurityManager::CheckChannelHasProtocolSecurityFlag(
1131 nsIChannel
* aChannel
) {
1132 nsCOMPtr
<nsIURI
> uri
;
1133 nsresult rv
= NS_GetFinalChannelURI(aChannel
, getter_AddRefs(uri
));
1134 NS_ENSURE_SUCCESS(rv
, rv
);
1136 nsAutoCString scheme
;
1137 rv
= uri
->GetScheme(scheme
);
1138 NS_ENSURE_SUCCESS(rv
, rv
);
1140 nsCOMPtr
<nsIIOService
> ios
= do_GetIOService(&rv
);
1141 NS_ENSURE_SUCCESS(rv
, rv
);
1143 nsCOMPtr
<nsIProtocolHandler
> handler
;
1144 rv
= ios
->GetProtocolHandler(scheme
.get(), getter_AddRefs(handler
));
1145 NS_ENSURE_SUCCESS(rv
, rv
);
1148 rv
= handler
->DoGetProtocolFlags(uri
, &flags
);
1149 NS_ENSURE_SUCCESS(rv
, rv
);
1151 uint32_t securityFlagsSet
= 0;
1152 if (flags
& nsIProtocolHandler::URI_LOADABLE_BY_ANYONE
) {
1153 securityFlagsSet
+= 1;
1155 if (flags
& nsIProtocolHandler::URI_DANGEROUS_TO_LOAD
) {
1156 securityFlagsSet
+= 1;
1158 if (flags
& nsIProtocolHandler::URI_IS_UI_RESOURCE
) {
1159 securityFlagsSet
+= 1;
1161 if (flags
& nsIProtocolHandler::URI_IS_LOCAL_FILE
) {
1162 securityFlagsSet
+= 1;
1164 if (flags
& nsIProtocolHandler::URI_LOADABLE_BY_SUBSUMERS
) {
1165 securityFlagsSet
+= 1;
1168 // Ensure that only "1" valid security flags is set.
1169 if (securityFlagsSet
== 1) {
1173 MOZ_ASSERT(false, "protocol must use one valid security flag");
1174 return NS_ERROR_CONTENT_BLOCKED
;
1178 * Based on the security flags provided in the loadInfo of the channel,
1179 * doContentSecurityCheck() performs the following content security checks
1180 * before opening the channel:
1182 * (1) Same Origin Policy Check (if applicable)
1183 * (2) Allow Cross Origin but perform sanity checks whether a principal
1184 * is allowed to access the following URL.
1185 * (3) Perform CORS check (if applicable)
1186 * (4) ContentPolicy checks (Content-Security-Policy, Mixed Content, ...)
1189 * The channel to perform the security checks on.
1190 * @param aInAndOutListener
1191 * The streamListener that is passed to channel->AsyncOpen() that is now
1192 * potentially wrappend within nsCORSListenerProxy() and becomes the
1193 * corsListener that now needs to be set as new streamListener on the channel.
1195 nsresult
nsContentSecurityManager::doContentSecurityCheck(
1196 nsIChannel
* aChannel
, nsCOMPtr
<nsIStreamListener
>& aInAndOutListener
) {
1197 NS_ENSURE_ARG(aChannel
);
1198 nsCOMPtr
<nsILoadInfo
> loadInfo
= aChannel
->LoadInfo();
1199 if (MOZ_UNLIKELY(MOZ_LOG_TEST(sCSMLog
, LogLevel::Verbose
))) {
1200 DebugDoContentSecurityCheck(aChannel
, loadInfo
);
1203 nsresult rv
= CheckAllowLoadInSystemPrivilegedContext(aChannel
);
1204 NS_ENSURE_SUCCESS(rv
, rv
);
1206 rv
= CheckChannelHasProtocolSecurityFlag(aChannel
);
1207 NS_ENSURE_SUCCESS(rv
, rv
);
1209 // if dealing with a redirected channel then we have already installed
1210 // streamlistener and redirect proxies and so we are done.
1211 if (loadInfo
->GetInitialSecurityCheckDone()) {
1215 // make sure that only one of the five security flags is set in the loadinfo
1216 // e.g. do not require same origin and allow cross origin at the same time
1217 rv
= ValidateSecurityFlags(loadInfo
);
1218 NS_ENSURE_SUCCESS(rv
, rv
);
1220 if (loadInfo
->GetSecurityMode() ==
1221 nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT
) {
1222 rv
= DoCORSChecks(aChannel
, loadInfo
, aInAndOutListener
);
1223 NS_ENSURE_SUCCESS(rv
, rv
);
1226 rv
= CheckChannel(aChannel
);
1227 NS_ENSURE_SUCCESS(rv
, rv
);
1229 // Perform all ContentPolicy checks (MixedContent, CSP, ...)
1230 rv
= DoContentSecurityChecks(aChannel
, loadInfo
);
1231 NS_ENSURE_SUCCESS(rv
, rv
);
1233 // Apply this after CSP to match Chrome.
1234 rv
= CheckFTPSubresourceLoad(aChannel
);
1235 NS_ENSURE_SUCCESS(rv
, rv
);
1237 // now lets set the initialSecurityFlag for subsequent calls
1238 loadInfo
->SetInitialSecurityCheckDone(true);
1240 // all security checks passed - lets allow the load
1245 nsContentSecurityManager::AsyncOnChannelRedirect(
1246 nsIChannel
* aOldChannel
, nsIChannel
* aNewChannel
, uint32_t aRedirFlags
,
1247 nsIAsyncVerifyRedirectCallback
* aCb
) {
1248 // Since we compare the principal from the loadInfo to the URI's
1249 // princicpal, it's possible that the checks fail when doing an internal
1250 // redirect. We can just return early instead, since we should never
1251 // need to block an internal redirect.
1252 if (aRedirFlags
& nsIChannelEventSink::REDIRECT_INTERNAL
) {
1253 aCb
->OnRedirectVerifyCallback(NS_OK
);
1257 nsCOMPtr
<nsILoadInfo
> loadInfo
= aOldChannel
->LoadInfo();
1258 nsresult rv
= CheckChannel(aNewChannel
);
1259 if (NS_SUCCEEDED(rv
)) {
1260 rv
= CheckFTPSubresourceLoad(aNewChannel
);
1262 if (NS_FAILED(rv
)) {
1263 aOldChannel
->Cancel(rv
);
1267 // Also verify that the redirecting server is allowed to redirect to the
1269 nsCOMPtr
<nsIPrincipal
> oldPrincipal
;
1270 nsContentUtils::GetSecurityManager()->GetChannelResultPrincipal(
1271 aOldChannel
, getter_AddRefs(oldPrincipal
));
1273 nsCOMPtr
<nsIURI
> newURI
;
1274 Unused
<< NS_GetFinalChannelURI(aNewChannel
, getter_AddRefs(newURI
));
1275 NS_ENSURE_STATE(oldPrincipal
&& newURI
);
1277 // Do not allow insecure redirects to data: URIs
1278 if (!AllowInsecureRedirectToDataURI(aNewChannel
)) {
1279 // cancel the old channel and return an error
1280 aOldChannel
->Cancel(NS_ERROR_CONTENT_BLOCKED
);
1281 return NS_ERROR_CONTENT_BLOCKED
;
1284 const uint32_t flags
=
1285 nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT
|
1286 nsIScriptSecurityManager::DISALLOW_SCRIPT
;
1287 rv
= nsContentUtils::GetSecurityManager()->CheckLoadURIWithPrincipal(
1288 oldPrincipal
, newURI
, flags
, loadInfo
->GetInnerWindowID());
1289 NS_ENSURE_SUCCESS(rv
, rv
);
1291 aCb
->OnRedirectVerifyCallback(NS_OK
);
1295 static void AddLoadFlags(nsIRequest
* aRequest
, nsLoadFlags aNewFlags
) {
1297 aRequest
->GetLoadFlags(&flags
);
1299 aRequest
->SetLoadFlags(flags
);
1303 * Check that this channel passes all security checks. Returns an error code
1304 * if this requesst should not be permitted.
1306 nsresult
nsContentSecurityManager::CheckChannel(nsIChannel
* aChannel
) {
1307 nsCOMPtr
<nsILoadInfo
> loadInfo
= aChannel
->LoadInfo();
1308 nsCOMPtr
<nsIURI
> uri
;
1309 nsresult rv
= NS_GetFinalChannelURI(aChannel
, getter_AddRefs(uri
));
1310 NS_ENSURE_SUCCESS(rv
, rv
);
1312 // Handle cookie policies
1313 uint32_t cookiePolicy
= loadInfo
->GetCookiePolicy();
1314 if (cookiePolicy
== nsILoadInfo::SEC_COOKIES_SAME_ORIGIN
) {
1315 // We shouldn't have the SEC_COOKIES_SAME_ORIGIN flag for top level loads
1316 MOZ_ASSERT(loadInfo
->GetExternalContentPolicyType() !=
1317 ExtContentPolicy::TYPE_DOCUMENT
);
1318 nsIPrincipal
* loadingPrincipal
= loadInfo
->GetLoadingPrincipal();
1320 // It doesn't matter what we pass for the second, data-inherits, argument.
1321 // Any protocol which inherits won't pay attention to cookies anyway.
1322 rv
= loadingPrincipal
->CheckMayLoad(uri
, false);
1323 if (NS_FAILED(rv
)) {
1324 AddLoadFlags(aChannel
, nsIRequest::LOAD_ANONYMOUS
);
1326 } else if (cookiePolicy
== nsILoadInfo::SEC_COOKIES_OMIT
) {
1327 AddLoadFlags(aChannel
, nsIRequest::LOAD_ANONYMOUS
);
1330 nsSecurityFlags securityMode
= loadInfo
->GetSecurityMode();
1332 // CORS mode is handled by nsCORSListenerProxy
1333 if (securityMode
== nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT
) {
1334 if (NS_HasBeenCrossOrigin(aChannel
)) {
1335 loadInfo
->MaybeIncreaseTainting(LoadTainting::CORS
);
1340 // Allow subresource loads if TriggeringPrincipal is the SystemPrincipal.
1341 if (loadInfo
->TriggeringPrincipal()->IsSystemPrincipal() &&
1342 loadInfo
->GetExternalContentPolicyType() !=
1343 ExtContentPolicy::TYPE_DOCUMENT
&&
1344 loadInfo
->GetExternalContentPolicyType() !=
1345 ExtContentPolicy::TYPE_SUBDOCUMENT
) {
1349 // if none of the REQUIRE_SAME_ORIGIN flags are set, then SOP does not apply
1350 if ((securityMode
==
1351 nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_INHERITS_SEC_CONTEXT
) ||
1352 (securityMode
== nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED
)) {
1353 rv
= DoSOPChecks(uri
, loadInfo
, aChannel
);
1354 NS_ENSURE_SUCCESS(rv
, rv
);
1357 if ((securityMode
==
1358 nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT
) ||
1360 nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL
)) {
1361 if (NS_HasBeenCrossOrigin(aChannel
)) {
1362 NS_ENSURE_FALSE(loadInfo
->GetDontFollowRedirects(), NS_ERROR_DOM_BAD_URI
);
1363 loadInfo
->MaybeIncreaseTainting(LoadTainting::Opaque
);
1365 // Please note that DoCheckLoadURIChecks should only be enforced for
1366 // cross origin requests. If the flag SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT
1367 // is set within the loadInfo, then then CheckLoadURIWithPrincipal is
1368 // performed within nsCorsListenerProxy
1369 rv
= DoCheckLoadURIChecks(uri
, loadInfo
);
1370 NS_ENSURE_SUCCESS(rv
, rv
);
1371 // TODO: Bug 1371237
1372 // consider calling SetBlockedRequest in
1373 // nsContentSecurityManager::CheckChannel
1379 // ==== nsIContentSecurityManager implementation =====
1382 nsContentSecurityManager::PerformSecurityCheck(
1383 nsIChannel
* aChannel
, nsIStreamListener
* aStreamListener
,
1384 nsIStreamListener
** outStreamListener
) {
1385 nsCOMPtr
<nsIStreamListener
> inAndOutListener
= aStreamListener
;
1386 nsresult rv
= doContentSecurityCheck(aChannel
, inAndOutListener
);
1387 NS_ENSURE_SUCCESS(rv
, rv
);
1389 inAndOutListener
.forget(outStreamListener
);