summaryrefslogtreecommitdiffstats
path: root/dom/security/nsContentSecurityManager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/security/nsContentSecurityManager.cpp')
-rw-r--r--dom/security/nsContentSecurityManager.cpp84
1 files changed, 84 insertions, 0 deletions
diff --git a/dom/security/nsContentSecurityManager.cpp b/dom/security/nsContentSecurityManager.cpp
index c4e1ed8e1..069e7d6a7 100644
--- a/dom/security/nsContentSecurityManager.cpp
+++ b/dom/security/nsContentSecurityManager.cpp
@@ -1,13 +1,16 @@
#include "nsContentSecurityManager.h"
+#include "nsEscape.h"
#include "nsIChannel.h"
#include "nsIHttpChannelInternal.h"
#include "nsIStreamListener.h"
#include "nsILoadInfo.h"
+#include "nsIOService.h"
#include "nsContentUtils.h"
#include "nsCORSListenerProxy.h"
#include "nsIStreamListener.h"
#include "nsIDocument.h"
#include "nsMixedContentBlocker.h"
+#include "nsNullPrincipal.h"
#include "mozilla/dom/Element.h"
@@ -15,6 +18,66 @@ NS_IMPL_ISUPPORTS(nsContentSecurityManager,
nsIContentSecurityManager,
nsIChannelEventSink)
+/* static */ bool
+nsContentSecurityManager::AllowTopLevelNavigationToDataURI(
+ nsIURI* aURI,
+ nsContentPolicyType aContentPolicyType,
+ nsIPrincipal* aTriggeringPrincipal,
+ bool aLoadFromExternal)
+{
+ // 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;
+ }
+ if (aContentPolicyType != nsIContentPolicy::TYPE_DOCUMENT) {
+ return true;
+ }
+ bool isDataURI =
+ (NS_SUCCEEDED(aURI->SchemeIs("data", &isDataURI)) && isDataURI);
+ if (!isDataURI) {
+ return true;
+ }
+ // Whitelist data: images as long as they are not SVGs
+ nsAutoCString filePath;
+ aURI->GetFilePath(filePath);
+ if (StringBeginsWith(filePath, NS_LITERAL_CSTRING("image/")) &&
+ !StringBeginsWith(filePath, NS_LITERAL_CSTRING("image/svg+xml"))) {
+ return true;
+ }
+ // Whitelist data: PDFs and JSON
+ if (StringBeginsWith(filePath, NS_LITERAL_CSTRING("application/pdf")) ||
+ StringBeginsWith(filePath, NS_LITERAL_CSTRING("application/json"))) {
+ return true;
+ }
+ if (!aLoadFromExternal &&
+ nsContentUtils::IsSystemPrincipal(aTriggeringPrincipal)) {
+ return true;
+ }
+ nsAutoCString dataSpec;
+ aURI->GetSpec(dataSpec);
+ if (dataSpec.Length() > 50) {
+ dataSpec.Truncate(50);
+ dataSpec.AppendLiteral("...");
+ }
+ NS_ConvertUTF8toUTF16 specUTF16(NS_UnescapeURL(dataSpec));
+ const char16_t* params[] = { specUTF16.get() };
+ nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
+ NS_LITERAL_CSTRING("DATA_URI_BLOCKED"),
+ // no doc available, log to browser console
+ nullptr,
+ nsContentUtils::eSECURITY_PROPERTIES,
+ "BlockTopLevelDataURINavigation",
+ params, ArrayLength(params));
+ return false;
+}
+
static nsresult
ValidateSecurityFlags(nsILoadInfo* aLoadInfo)
{
@@ -478,6 +541,27 @@ nsContentSecurityManager::AsyncOnChannelRedirect(nsIChannel* aOldChannel,
}
}
+ // Redirecting to a toplevel data: URI is not allowed, hence we pass
+ // a NullPrincipal as the TriggeringPrincipal to
+ // AllowTopLevelNavigationToDataURI() which definitely blocks any
+ // data: URI load.
+ nsCOMPtr<nsILoadInfo> newLoadInfo = aNewChannel->GetLoadInfo();
+ if (newLoadInfo) {
+ nsCOMPtr<nsIURI> uri;
+ nsresult rv = NS_GetFinalChannelURI(aNewChannel, getter_AddRefs(uri));
+ NS_ENSURE_SUCCESS(rv, rv);
+ nsCOMPtr<nsIPrincipal> nullTriggeringPrincipal = nsNullPrincipal::Create();
+ if (!nsContentSecurityManager::AllowTopLevelNavigationToDataURI(
+ uri,
+ newLoadInfo->GetExternalContentPolicyType(),
+ nullTriggeringPrincipal,
+ false)) {
+ // logging to console happens within AllowTopLevelNavigationToDataURI
+ aOldChannel->Cancel(NS_ERROR_DOM_BAD_URI);
+ return NS_ERROR_DOM_BAD_URI;
+ }
+ }
+
// Also verify that the redirecting server is allowed to redirect to the
// given URI
nsCOMPtr<nsIPrincipal> oldPrincipal;