diff options
Diffstat (limited to 'dom/security/nsContentSecurityManager.cpp')
-rw-r--r-- | dom/security/nsContentSecurityManager.cpp | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/dom/security/nsContentSecurityManager.cpp b/dom/security/nsContentSecurityManager.cpp index c4e1ed8e18..069e7d6a70 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; |