Bug 536509 - Update localStorage to use common StorageAllowedForWindow logic, r=ehsan

This commit is contained in:
Michael Layzell 2015-07-15 16:44:42 -04:00
Родитель 868a200adc
Коммит c84994fb3c
7 изменённых файлов: 76 добавлений и 59 удалений

Просмотреть файл

@ -10910,7 +10910,7 @@ nsGlobalWindow::GetLocalStorage(ErrorResult& aError)
} }
if (!mLocalStorage) { if (!mLocalStorage) {
if (!DOMStorage::CanUseStorage()) { if (!DOMStorage::CanUseStorage(this)) {
aError.Throw(NS_ERROR_DOM_SECURITY_ERR); aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
return nullptr; return nullptr;
} }
@ -10928,13 +10928,6 @@ nsGlobalWindow::GetLocalStorage(ErrorResult& aError)
return nullptr; return nullptr;
} }
// If the document has the sandboxed origin flag set
// don't allow access to localStorage.
if (mDoc && (mDoc->GetSandboxFlags() & SANDBOXED_ORIGIN)) {
aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
return nullptr;
}
nsString documentURI; nsString documentURI;
if (mDoc) { if (mDoc) {
mDoc->GetDocumentURI(documentURI); mDoc->GetDocumentURI(documentURI);

Просмотреть файл

@ -13,13 +13,14 @@
#include "nsIPermissionManager.h" #include "nsIPermissionManager.h"
#include "nsIPrincipal.h" #include "nsIPrincipal.h"
#include "nsICookiePermission.h" #include "nsICookiePermission.h"
#include "nsICookieService.h" #include "nsPIDOMWindow.h"
#include "mozilla/dom/StorageBinding.h" #include "mozilla/dom/StorageBinding.h"
#include "mozilla/dom/StorageEvent.h" #include "mozilla/dom/StorageEvent.h"
#include "mozilla/dom/StorageEventBinding.h" #include "mozilla/dom/StorageEventBinding.h"
#include "mozilla/Services.h" #include "mozilla/Services.h"
#include "mozilla/Preferences.h" #include "mozilla/Preferences.h"
#include "mozilla/EnumSet.h"
#include "nsThreadUtils.h" #include "nsThreadUtils.h"
#include "nsContentUtils.h" #include "nsContentUtils.h"
#include "nsServiceManagerUtils.h" #include "nsServiceManagerUtils.h"
@ -70,7 +71,7 @@ DOMStorage::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
uint32_t uint32_t
DOMStorage::GetLength(ErrorResult& aRv) DOMStorage::GetLength(ErrorResult& aRv)
{ {
if (!CanUseStorage(this)) { if (!CanUseStorage(nullptr, this)) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return 0; return 0;
} }
@ -83,7 +84,7 @@ DOMStorage::GetLength(ErrorResult& aRv)
void void
DOMStorage::Key(uint32_t aIndex, nsAString& aResult, ErrorResult& aRv) DOMStorage::Key(uint32_t aIndex, nsAString& aResult, ErrorResult& aRv)
{ {
if (!CanUseStorage(this)) { if (!CanUseStorage(nullptr, this)) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return; return;
} }
@ -94,7 +95,7 @@ DOMStorage::Key(uint32_t aIndex, nsAString& aResult, ErrorResult& aRv)
void void
DOMStorage::GetItem(const nsAString& aKey, nsAString& aResult, ErrorResult& aRv) DOMStorage::GetItem(const nsAString& aKey, nsAString& aResult, ErrorResult& aRv)
{ {
if (!CanUseStorage(this)) { if (!CanUseStorage(nullptr, this)) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return; return;
} }
@ -106,7 +107,7 @@ void
DOMStorage::SetItem(const nsAString& aKey, const nsAString& aData, DOMStorage::SetItem(const nsAString& aKey, const nsAString& aData,
ErrorResult& aRv) ErrorResult& aRv)
{ {
if (!CanUseStorage(this)) { if (!CanUseStorage(nullptr, this)) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return; return;
} }
@ -139,7 +140,7 @@ DOMStorage::SetItem(const nsAString& aKey, const nsAString& aData,
void void
DOMStorage::RemoveItem(const nsAString& aKey, ErrorResult& aRv) DOMStorage::RemoveItem(const nsAString& aKey, ErrorResult& aRv)
{ {
if (!CanUseStorage(this)) { if (!CanUseStorage(nullptr, this)) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return; return;
} }
@ -158,7 +159,7 @@ DOMStorage::RemoveItem(const nsAString& aKey, ErrorResult& aRv)
void void
DOMStorage::Clear(ErrorResult& aRv) DOMStorage::Clear(ErrorResult& aRv)
{ {
if (!CanUseStorage(this)) { if (!CanUseStorage(nullptr, this)) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return; return;
} }
@ -236,60 +237,32 @@ static const char kCookiesLifetimePolicy[] = "network.cookie.lifetimePolicy";
// static, public // static, public
bool bool
DOMStorage::CanUseStorage(DOMStorage* aStorage) DOMStorage::CanUseStorage(nsPIDOMWindow* aWindow, DOMStorage* aStorage)
{ {
// This method is responsible for correct setting of mIsSessionOnly. // This method is responsible for correct setting of mIsSessionOnly.
// It doesn't work with mIsPrivate flag at all, since it is checked // It doesn't work with mIsPrivate flag at all, since it is checked
// regardless mIsSessionOnly flag in DOMStorageCache code. // regardless mIsSessionOnly flag in DOMStorageCache code.
if (aStorage) {
aStorage->mIsSessionOnly = false;
}
if (!mozilla::Preferences::GetBool(kStorageEnabled)) { if (!mozilla::Preferences::GetBool(kStorageEnabled)) {
return false; return false;
} }
// chrome can always use aStorage regardless of permission preferences nsContentUtils::StorageAccess access = nsContentUtils::StorageAccess::eDeny;
nsCOMPtr<nsIPrincipal> subjectPrincipal = if (aWindow) {
nsContentUtils::SubjectPrincipal(); access = nsContentUtils::StorageAllowedForWindow(aWindow);
if (nsContentUtils::IsSystemPrincipal(subjectPrincipal)) { } else if (aStorage) {
return true; access = nsContentUtils::StorageAllowedForPrincipal(aStorage->mPrincipal);
} }
nsCOMPtr<nsIPermissionManager> permissionManager = if (access == nsContentUtils::StorageAccess::eDeny) {
services::GetPermissionManager();
if (!permissionManager) {
return false; return false;
} }
uint32_t perm;
permissionManager->TestPermissionFromPrincipal(subjectPrincipal,
kPermissionType, &perm);
if (perm == nsIPermissionManager::DENY_ACTION) {
return false;
}
if (perm == nsICookiePermission::ACCESS_SESSION) {
if (aStorage) {
aStorage->mIsSessionOnly = true;
}
} else if (perm != nsIPermissionManager::ALLOW_ACTION) {
uint32_t cookieBehavior = Preferences::GetUint(kCookiesBehavior);
uint32_t lifetimePolicy = Preferences::GetUint(kCookiesLifetimePolicy);
// Treat "ask every time" as "reject always".
if (cookieBehavior == nsICookieService::BEHAVIOR_REJECT ||
lifetimePolicy == nsICookieService::ASK_BEFORE_ACCEPT) {
return false;
}
if (lifetimePolicy == nsICookieService::ACCEPT_SESSION && aStorage) {
aStorage->mIsSessionOnly = true;
}
}
if (aStorage) { if (aStorage) {
aStorage->mIsSessionOnly = access <= nsContentUtils::StorageAccess::eSessionScoped;
nsCOMPtr<nsIPrincipal> subjectPrincipal =
nsContentUtils::SubjectPrincipal();
return aStorage->CanAccess(subjectPrincipal); return aStorage->CanAccess(subjectPrincipal);
} }
@ -327,7 +300,7 @@ DOMStorage::CanAccess(nsIPrincipal* aPrincipal)
void void
DOMStorage::GetSupportedNames(unsigned, nsTArray<nsString>& aKeys) DOMStorage::GetSupportedNames(unsigned, nsTArray<nsString>& aKeys)
{ {
if (!CanUseStorage(this)) { if (!CanUseStorage(nullptr, this)) {
// return just an empty array // return just an empty array
aKeys.Clear(); aKeys.Clear();
return; return;

Просмотреть файл

@ -18,6 +18,7 @@
class nsIPrincipal; class nsIPrincipal;
class nsIDOMWindow; class nsIDOMWindow;
class nsPIDOMWindow;
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
@ -122,7 +123,7 @@ public:
// It is an optimization since the privileges check and session only // It is an optimization since the privileges check and session only
// state determination are complex and share the code (comes hand in // state determination are complex and share the code (comes hand in
// hand together). // hand together).
static bool CanUseStorage(DOMStorage* aStorage = nullptr); static bool CanUseStorage(nsPIDOMWindow* aWindow, DOMStorage* aStorage = nullptr);
bool IsPrivate() const { return mIsPrivate; } bool IsPrivate() const { return mIsPrivate; }
bool IsSessionOnly() const { return mIsSessionOnly; } bool IsSessionOnly() const { return mIsSessionOnly; }

Просмотреть файл

@ -0,0 +1,20 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>localStorage cookies settings test</title>
<script type="text/javascript" src="interOriginFrame.js"></script>
</head>
<body>
<script type="text/javascript">
try {
localStorage.setItem("contentkey", "test-value");
ok(false, "Setting localStorageItem should throw a security exception");
} catch(ex) {
is(ex.name, "SecurityError");
}
finishTest();
</script>
</body>
</html>

Просмотреть файл

@ -49,7 +49,9 @@ function todo(a, b, message)
function finishTest() function finishTest()
{ {
localStorage.clear(); try {
localStorage.clear();
} catch (e) {}
postMsg("done"); postMsg("done");
return false; return false;
} }

Просмотреть файл

@ -2,6 +2,7 @@
support-files = support-files =
frameAppIsolation.html frameAppIsolation.html
frameChromeSlave.html frameChromeSlave.html
frameLocalStorageCookieSettings.html
frameKeySync.html frameKeySync.html
frameMasterEqual.html frameMasterEqual.html
frameMasterNotEqual.html frameMasterNotEqual.html

Просмотреть файл

@ -3,8 +3,13 @@
<title>localStorage cookies settings test</title> <title>localStorage cookies settings test</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="interOriginTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<iframe></iframe>
<script type="text/javascript"> <script type="text/javascript">
SimpleTest.waitForExplicitFinish(); SimpleTest.waitForExplicitFinish();
@ -37,11 +42,33 @@ function test2() {
is(ex.name, "SecurityError"); is(ex.name, "SecurityError");
} }
// Set cookies behavior to "reject 3rd party"
SpecialPowers.pushPrefEnv({"set": [["network.cookie.cookieBehavior", 1]],
"clear": [["network.cookie.lifetimePolicy"]]},
test3);
}
function test3() {
try {
localStorage.setItem("contentkey", "test-value");
ok(true, "Setting localStorageItem should not throw a security exception");
}
catch(ex) {
ok(false, "Setting localStorageItem should not throw a security exception");
}
var fileTest = (location.protocol + "//example.com" + location.pathname)
.replace("test_l", "frameL");
var myframe = document.querySelector("iframe");
myframe.src = fileTest;
}
// Called by interOriginTest.js
function doNextTest() {
SimpleTest.finish(); SimpleTest.finish();
} }
</script> </script>
</head>
<body>
</body> </body>
</html> </html>