зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1184973 - Part 1: Add nsContentUtils::StorageAllowedForWindow as a unified mechanism for determining storage avaliability, r=ehsan, r=smaug
This commit is contained in:
Родитель
19eddf8198
Коммит
7547c928d3
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче