Bug 1184973 - Part 1: Add nsContentUtils::StorageAllowedForWindow as a unified mechanism for determining storage avaliability, r=ehsan, r=smaug

This commit is contained in:
Michael Layzell 2015-07-15 16:41:28 -04:00
parent 9a2836bb5f
commit 1058576c02
2 changed files with 193 additions and 0 deletions

View File

@ -192,6 +192,10 @@
#include "xpcprivate.h" // nsXPConnect
#include "HTMLSplitOnSpacesTokenizer.h"
#include "nsContentTypeParser.h"
#include "nsICookiePermission.h"
#include "mozIThirdPartyUtil.h"
#include "nsICookieService.h"
#include "mozilla/EnumSet.h"
#include "nsIBidiKeyboard.h"
@ -266,6 +270,9 @@ bool nsContentUtils::sSendPerformanceTimingNotifications = false;
uint32_t nsContentUtils::sHandlingInputTimeout = 1000;
uint32_t nsContentUtils::sCookiesLifetimePolicy = nsICookieService::ACCEPT_NORMALLY;
uint32_t nsContentUtils::sCookiesBehavior = nsICookieService::BEHAVIOR_ACCEPT;
nsHtml5StringParser* nsContentUtils::sHTMLFragmentParser = nullptr;
nsIParser* nsContentUtils::sXMLFragmentParser = nullptr;
nsIFragmentContentSink* nsContentUtils::sXMLFragmentSink = nullptr;
@ -559,6 +566,14 @@ nsContentUtils::Init()
Preferences::AddBoolVarCache(&sSendPerformanceTimingNotifications,
"dom.performance.enable_notify_performance_timing", false);
Preferences::AddUintVarCache(&sCookiesLifetimePolicy,
"network.cookie.lifetimePolicy",
nsICookieService::ACCEPT_NORMALLY);
Preferences::AddUintVarCache(&sCookiesBehavior,
"network.cookie.cookieBehavior",
nsICookieService::BEHAVIOR_ACCEPT);
#if !(defined(DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
Preferences::AddBoolVarCache(&sDOMWindowDumpEnabled,
"browser.dom.window.dump.enabled");
@ -8055,3 +8070,135 @@ nsContentUtils::PushEnabled(JSContext* aCx, JSObject* aObj)
return workerPrivate->PushEnabled();
}
// static, public
nsContentUtils::StorageAccess
nsContentUtils::StorageAllowedForWindow(nsPIDOMWindow* aWindow)
{
MOZ_ASSERT(aWindow->IsInnerWindow());
nsIDocument* document = aWindow->GetExtantDoc();
if (document) {
nsCOMPtr<nsIPrincipal> principal = document->NodePrincipal();
return InternalStorageAllowedForPrincipal(principal, aWindow);
}
return StorageAccess::eDeny;
}
// static, public
nsContentUtils::StorageAccess
nsContentUtils::StorageAllowedForPrincipal(nsIPrincipal* aPrincipal)
{
return InternalStorageAllowedForPrincipal(aPrincipal, nullptr);
}
// static, private
nsContentUtils::StorageAccess
nsContentUtils::InternalStorageAllowedForPrincipal(nsIPrincipal* aPrincipal,
nsPIDOMWindow* aWindow)
{
MOZ_ASSERT(aPrincipal);
MOZ_ASSERT(!aWindow || aWindow->IsInnerWindow());
StorageAccess access = StorageAccess::eAllow;
// We don't allow storage on the null principal, in general. Even if the
// calling context is chrome.
bool isNullPrincipal;
if (NS_WARN_IF(NS_FAILED(aPrincipal->GetIsNullPrincipal(&isNullPrincipal))) ||
isNullPrincipal) {
return StorageAccess::eDeny;
}
if (aWindow) {
// If the document is sandboxed, then it is not permitted to use storage
nsIDocument* document = aWindow->GetExtantDoc();
if (document->GetSandboxFlags() & SANDBOXED_ORIGIN) {
return StorageAccess::eDeny;
}
// Check if we are in private browsing, and record that fact
if (IsInPrivateBrowsing(document)) {
access = StorageAccess::ePrivateBrowsing;
}
}
// Check if we should only allow storage for the session, and record that fact
if (sCookiesLifetimePolicy == nsICookieService::ACCEPT_SESSION) {
// Storage could be StorageAccess::ePrivateBrowsing or StorageAccess::eAllow
// so perform a std::min comparison to make sure we preserve ePrivateBrowsing
// if it has been set.
access = std::min(StorageAccess::eSessionScoped, access);
}
// If the caller is chrome privileged, then it is allowed to access any
// storage it likes, no matter whether the storage for that window/principal
// would normally be permitted.
if (IsSystemPrincipal(SubjectPrincipal())) {
return access;
}
if (!SubjectPrincipal()->Subsumes(aPrincipal)) {
NS_WARNING("A principal is attempting to access storage for a principal "
"which it doesn't subsume!");
return StorageAccess::eDeny;
}
// About URIs are allowed to access storage, even if they don't have chrome
// privileges. If this is not desired, than the consumer will have to
// implement their own restriction functionality.
nsCOMPtr<nsIURI> uri;
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(aPrincipal->GetURI(getter_AddRefs(uri))));
bool isAbout = false;
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(uri->SchemeIs("about", &isAbout)));
if (isAbout) {
return access;
}
nsCOMPtr<nsIPermissionManager> permissionManager =
services::GetPermissionManager();
if (!permissionManager) {
return StorageAccess::eDeny;
}
// check the permission manager for any allow or deny permissions
// for cookies for the window.
uint32_t perm;
permissionManager->TestPermissionFromPrincipal(aPrincipal, "cookie", &perm);
if (perm == nsIPermissionManager::DENY_ACTION) {
return StorageAccess::eDeny;
} else if (perm == nsICookiePermission::ACCESS_SESSION) {
return std::min(access, StorageAccess::eSessionScoped);
} else if (perm == nsIPermissionManager::ALLOW_ACTION) {
return access;
}
// We don't want to prompt for every attempt to access permissions, so we
// treat the cookie ASK_BEFORE_ACCEPT as though it was a reject.
if (sCookiesBehavior == nsICookieService::BEHAVIOR_REJECT ||
sCookiesLifetimePolicy == nsICookieService::ASK_BEFORE_ACCEPT) {
return StorageAccess::eDeny;
}
// In the absense of a window, we assume that we are first-party.
if (aWindow && (sCookiesBehavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN ||
sCookiesBehavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN)) {
nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
do_GetService(THIRDPARTYUTIL_CONTRACTID);
MOZ_ASSERT(thirdPartyUtil);
bool thirdPartyWindow = false;
if (NS_SUCCEEDED(thirdPartyUtil->IsThirdPartyWindow(
aWindow, nullptr, &thirdPartyWindow)) && thirdPartyWindow) {
// XXX For non-cookie forms of storage, we handle BEHAVIOR_LIMIT_FOREIGN by
// simply rejecting the request to use the storage. In the future, if we
// change the meaning of BEHAVIOR_LIMIT_FOREIGN to be one which makes sense
// for non-cookie storage types, this may change.
return StorageAccess::eDeny;
}
}
return access;
}

View File

@ -2476,6 +2476,38 @@ public:
static bool PushEnabled(JSContext* aCx, JSObject* aObj);
// The order of these entries matters, as we use std::min for total ordering
// of permissions. Private Browsing is considered to be more limiting
// then session scoping
enum class StorageAccess {
// Don't allow access to the storage
eDeny = 0,
// Allow access to the storage, but only if it is secure to do so in a
// private browsing context.
ePrivateBrowsing = 1,
// Allow access to the storage, but only persist it for the current session
eSessionScoped = 2,
// Allow access to the storage
eAllow = 3,
};
/*
* Checks if storage for the given window is permitted by a combination of
* the user's preferences, and whether the window is a third-party iframe.
*
* This logic is intended to be shared between the different forms of
* persistent storage which are available to web pages. Cookies don't use
* this logic, and security logic related to them must be updated separately.
*/
static StorageAccess StorageAllowedForWindow(nsPIDOMWindow* aWindow);
/*
* Checks if storage for the given principal is permitted by the user's
* preferences. The caller is assumed to not be a third-party iframe.
* (if that is possible, the caller should use StorageAllowedForWindow)
*/
static StorageAccess StorageAllowedForPrincipal(nsIPrincipal* aPrincipal);
private:
static bool InitializeEventTable();
@ -2516,6 +2548,18 @@ private:
CallOnRemoteChildFunction aCallback,
void* aArg);
/*
* Checks if storage for a given principal is permitted by the user's
* preferences. If aWindow is non-null, its principal must be passed as
* aPrincipal, and the third-party iframe and sandboxing status of the window
* are also checked.
*
* Used in the implementation of StorageAllowedForWindow and
* StorageAllowedForPrincipal.
*/
static StorageAccess InternalStorageAllowedForPrincipal(nsIPrincipal* aPrincipal,
nsPIDOMWindow* aWindow);
static nsIXPConnect *sXPConnect;
static nsIScriptSecurityManager *sSecurityManager;
@ -2581,6 +2625,8 @@ private:
static bool sGettersDecodeURLHash;
static bool sPrivacyResistFingerprinting;
static bool sSendPerformanceTimingNotifications;
static uint32_t sCookiesLifetimePolicy;
static uint32_t sCookiesBehavior;
static nsHtml5StringParser* sHTMLFragmentParser;
static nsIParser* sXMLFragmentParser;