зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1731982 - Part 6: Use the client's principal to verify client in localStorage. r=asuth
Currently, we use the script principal to verify the client to prevent the principal forgery. After we moving to use foreign partitioned principal for the Client, this no longer works. Instead, we can directly use the client's principal to verify client. Also, the patch rename StoragePrincipalHelper::VerifyValidStoragePrincipalInfoForPrincipalInfo() to StoragePrincipalHelper::VerifyValidPartitionedPrincipalInfoForPrincipalInfo() and fix a problem in the function that it should ignore the PartitionKey instead of the FirstPartyDomain. Differential Revision: https://phabricator.services.mozilla.com/D127840
This commit is contained in:
Родитель
e65d0db962
Коммит
45bfad05fe
|
@ -3016,16 +3016,31 @@ void ForceKillAllDatabases() {
|
|||
}
|
||||
|
||||
bool VerifyPrincipalInfo(const PrincipalInfo& aPrincipalInfo,
|
||||
const PrincipalInfo& aStoragePrincipalInfo) {
|
||||
const PrincipalInfo& aStoragePrincipalInfo,
|
||||
bool aCheckClientPrincipal) {
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
if (NS_WARN_IF(!QuotaManager::IsPrincipalInfoValid(aPrincipalInfo))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!StoragePrincipalHelper::
|
||||
VerifyValidStoragePrincipalInfoForPrincipalInfo(
|
||||
aStoragePrincipalInfo, aPrincipalInfo))) {
|
||||
// Note that the client prinicpal could have a different spec than the node
|
||||
// principal but they should have the same origin. It's because the client
|
||||
// could be initialized when opening the initial about:blank document and pass
|
||||
// to the newly opened window and reuse over there if the new window has the
|
||||
// same origin as the initial about:blank document. But, the FilePath could be
|
||||
// different. Therefore, we have to ignore comparing the Spec of the
|
||||
// principals if we are verifying clinet principal here. Also, when
|
||||
// document.domain is set, client principal won't get it. So, we don't compare
|
||||
// domain for client princpal too.
|
||||
bool result = aCheckClientPrincipal
|
||||
? StoragePrincipalHelper::
|
||||
VerifyValidClientPrincipalInfoForPrincipalInfo(
|
||||
aStoragePrincipalInfo, aPrincipalInfo)
|
||||
: StoragePrincipalHelper::
|
||||
VerifyValidStoragePrincipalInfoForPrincipalInfo(
|
||||
aStoragePrincipalInfo, aPrincipalInfo);
|
||||
if (NS_WARN_IF(!result)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -3033,7 +3048,7 @@ bool VerifyPrincipalInfo(const PrincipalInfo& aPrincipalInfo,
|
|||
}
|
||||
|
||||
bool VerifyClientId(const Maybe<ContentParentId>& aContentParentId,
|
||||
const PrincipalInfo& aPrincipalInfo,
|
||||
const Maybe<PrincipalInfo>& aPrincipalInfo,
|
||||
const Maybe<nsID>& aClientId) {
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
|
@ -3042,9 +3057,13 @@ bool VerifyClientId(const Maybe<ContentParentId>& aContentParentId,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(aPrincipalInfo.isNothing())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<ClientManagerService> svc = ClientManagerService::GetInstance();
|
||||
if (svc && NS_WARN_IF(!svc->HasWindow(aContentParentId, aPrincipalInfo,
|
||||
aClientId.ref()))) {
|
||||
if (svc && NS_WARN_IF(!svc->HasWindow(
|
||||
aContentParentId, aPrincipalInfo.ref(), aClientId.ref()))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -6074,8 +6093,8 @@ bool LSRequestBase::VerifyRequestParams() {
|
|||
const LSRequestCommonParams& params =
|
||||
mParams.get_LSRequestPreloadDatastoreParams().commonParams();
|
||||
|
||||
if (NS_WARN_IF(!VerifyPrincipalInfo(params.principalInfo(),
|
||||
params.storagePrincipalInfo()))) {
|
||||
if (NS_WARN_IF(!VerifyPrincipalInfo(
|
||||
params.principalInfo(), params.storagePrincipalInfo(), false))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -6093,14 +6112,21 @@ bool LSRequestBase::VerifyRequestParams() {
|
|||
|
||||
const LSRequestCommonParams& commonParams = params.commonParams();
|
||||
|
||||
if (NS_WARN_IF(
|
||||
!VerifyPrincipalInfo(commonParams.principalInfo(),
|
||||
commonParams.storagePrincipalInfo()))) {
|
||||
if (NS_WARN_IF(!VerifyPrincipalInfo(commonParams.principalInfo(),
|
||||
commonParams.storagePrincipalInfo(),
|
||||
false))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (params.clientPrincipalInfo() &&
|
||||
NS_WARN_IF(!VerifyPrincipalInfo(commonParams.principalInfo(),
|
||||
params.clientPrincipalInfo().ref(),
|
||||
true))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!VerifyClientId(mContentParentId,
|
||||
commonParams.principalInfo(),
|
||||
params.clientPrincipalInfo(),
|
||||
params.clientId()))) {
|
||||
return false;
|
||||
}
|
||||
|
@ -6117,12 +6143,20 @@ bool LSRequestBase::VerifyRequestParams() {
|
|||
const LSRequestPrepareObserverParams& params =
|
||||
mParams.get_LSRequestPrepareObserverParams();
|
||||
|
||||
if (NS_WARN_IF(!VerifyPrincipalInfo(params.principalInfo(),
|
||||
params.storagePrincipalInfo()))) {
|
||||
if (NS_WARN_IF(!VerifyPrincipalInfo(
|
||||
params.principalInfo(), params.storagePrincipalInfo(), false))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!VerifyClientId(mContentParentId, params.principalInfo(),
|
||||
if (params.clientPrincipalInfo() &&
|
||||
NS_WARN_IF(!VerifyPrincipalInfo(params.principalInfo(),
|
||||
params.clientPrincipalInfo().ref(),
|
||||
true))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!VerifyClientId(mContentParentId,
|
||||
params.clientPrincipalInfo(),
|
||||
params.clientId()))) {
|
||||
return false;
|
||||
}
|
||||
|
@ -7751,8 +7785,8 @@ bool LSSimpleRequestBase::VerifyRequestParams() {
|
|||
const LSSimpleRequestPreloadedParams& params =
|
||||
mParams.get_LSSimpleRequestPreloadedParams();
|
||||
|
||||
if (NS_WARN_IF(!VerifyPrincipalInfo(params.principalInfo(),
|
||||
params.storagePrincipalInfo()))) {
|
||||
if (NS_WARN_IF(!VerifyPrincipalInfo(
|
||||
params.principalInfo(), params.storagePrincipalInfo(), false))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
#include "mozilla/ipc/BackgroundChild.h"
|
||||
#include "mozilla/ipc/BackgroundUtils.h"
|
||||
#include "mozilla/ipc/PBackgroundChild.h"
|
||||
#include "mozilla/ipc/PBackgroundSharedTypes.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsDebug.h"
|
||||
|
@ -363,6 +362,9 @@ nsresult LSObject::CreateForWindow(nsPIDOMWindowInner* aWindow,
|
|||
|
||||
Maybe<nsID> clientId = Some(clientInfo.ref().Id());
|
||||
|
||||
Maybe<PrincipalInfo> clientPrincipalInfo =
|
||||
Some(clientInfo.ref().PrincipalInfo());
|
||||
|
||||
nsString documentURI;
|
||||
if (nsCOMPtr<Document> doc = aWindow->GetExtantDoc()) {
|
||||
rv = doc->GetDocumentURI(documentURI);
|
||||
|
@ -376,6 +378,7 @@ nsresult LSObject::CreateForWindow(nsPIDOMWindowInner* aWindow,
|
|||
object->mStoragePrincipalInfo = std::move(storagePrincipalInfo);
|
||||
object->mPrivateBrowsingId = privateBrowsingId;
|
||||
object->mClientId = clientId;
|
||||
object->mClientPrincipalInfo = clientPrincipalInfo;
|
||||
object->mOrigin = origin;
|
||||
object->mOriginKey = originKey;
|
||||
object->mDocumentURI = documentURI;
|
||||
|
@ -932,6 +935,7 @@ nsresult LSObject::EnsureDatabase() {
|
|||
LSRequestPrepareDatastoreParams params;
|
||||
params.commonParams() = commonParams;
|
||||
params.clientId() = mClientId;
|
||||
params.clientPrincipalInfo() = mClientPrincipalInfo;
|
||||
|
||||
LSRequestResponse response;
|
||||
|
||||
|
@ -992,6 +996,7 @@ nsresult LSObject::EnsureObserver() {
|
|||
params.principalInfo() = *mPrincipalInfo;
|
||||
params.storagePrincipalInfo() = *mStoragePrincipalInfo;
|
||||
params.clientId() = mClientId;
|
||||
params.clientPrincipalInfo() = mClientPrincipalInfo;
|
||||
|
||||
LSRequestResponse response;
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/dom/Storage.h"
|
||||
#include "mozilla/ipc/PBackgroundSharedTypes.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsID.h"
|
||||
#include "nsISupports.h"
|
||||
|
@ -31,12 +32,6 @@ namespace mozilla {
|
|||
|
||||
class ErrorResult;
|
||||
|
||||
namespace ipc {
|
||||
|
||||
class PrincipalInfo;
|
||||
|
||||
} // namespace ipc
|
||||
|
||||
namespace dom {
|
||||
|
||||
class LSDatabase;
|
||||
|
@ -82,6 +77,7 @@ class LSObject final : public Storage {
|
|||
|
||||
uint32_t mPrivateBrowsingId;
|
||||
Maybe<nsID> mClientId;
|
||||
Maybe<PrincipalInfo> mClientPrincipalInfo;
|
||||
nsCString mOrigin;
|
||||
nsCString mOriginKey;
|
||||
nsString mDocumentURI;
|
||||
|
|
|
@ -29,13 +29,30 @@ struct LSRequestPrepareDatastoreParams
|
|||
{
|
||||
LSRequestCommonParams commonParams;
|
||||
nsID? clientId;
|
||||
PrincipalInfo? clientPrincipalInfo;
|
||||
};
|
||||
|
||||
/**
|
||||
* In order to validate the principal with the client, we need to provide an
|
||||
* additional principalInfo for the client. The client is using the foreign
|
||||
* principal, see StoragePrincipalHelper.h for details, which is different from
|
||||
* the principalInfo. So, we need to pass the principalInfo from the client So
|
||||
* that we can verify it with the given client Id.
|
||||
*
|
||||
* Note that the storagePrincipalInfo is used to access the right cookie jar
|
||||
* according to the Storage Access. This is passed in order to access the
|
||||
* correct local storage. Essentially, the storage principal and the client
|
||||
* principal are using the PartitionKey in their OriginAttributes. But, the
|
||||
* existence of the PartitionKey between them is depending on different
|
||||
* conditions. Namely, the storage principal depends on the Storage Access but
|
||||
* the client principal depends on whether it's in a third party.
|
||||
*/
|
||||
struct LSRequestPrepareObserverParams
|
||||
{
|
||||
PrincipalInfo principalInfo;
|
||||
PrincipalInfo storagePrincipalInfo;
|
||||
nsID? clientId;
|
||||
PrincipalInfo? clientPrincipalInfo;
|
||||
};
|
||||
|
||||
union LSRequestParams
|
||||
|
|
|
@ -84,6 +84,78 @@ bool ChooseOriginAttributes(nsIChannel* aChannel, OriginAttributes& aAttrs,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool VerifyValidPartitionedPrincipalInfoForPrincipalInfoInternal(
|
||||
const ipc::PrincipalInfo& aPartitionedPrincipalInfo,
|
||||
const ipc::PrincipalInfo& aPrincipalInfo,
|
||||
bool aIgnoreSpecForContentPrincipal,
|
||||
bool aIgnoreDomainForContentPrincipal) {
|
||||
if (aPartitionedPrincipalInfo.type() != aPrincipalInfo.type()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aPartitionedPrincipalInfo.type() ==
|
||||
mozilla::ipc::PrincipalInfo::TContentPrincipalInfo) {
|
||||
const mozilla::ipc::ContentPrincipalInfo& spInfo =
|
||||
aPartitionedPrincipalInfo.get_ContentPrincipalInfo();
|
||||
const mozilla::ipc::ContentPrincipalInfo& pInfo =
|
||||
aPrincipalInfo.get_ContentPrincipalInfo();
|
||||
|
||||
return spInfo.attrs().EqualsIgnoringPartitionKey(pInfo.attrs()) &&
|
||||
spInfo.originNoSuffix() == pInfo.originNoSuffix() &&
|
||||
(aIgnoreSpecForContentPrincipal || spInfo.spec() == pInfo.spec()) &&
|
||||
(aIgnoreDomainForContentPrincipal ||
|
||||
spInfo.domain() == pInfo.domain()) &&
|
||||
spInfo.baseDomain() == pInfo.baseDomain();
|
||||
}
|
||||
|
||||
if (aPartitionedPrincipalInfo.type() ==
|
||||
mozilla::ipc::PrincipalInfo::TSystemPrincipalInfo) {
|
||||
// Nothing to check here.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aPartitionedPrincipalInfo.type() ==
|
||||
mozilla::ipc::PrincipalInfo::TNullPrincipalInfo) {
|
||||
const mozilla::ipc::NullPrincipalInfo& spInfo =
|
||||
aPartitionedPrincipalInfo.get_NullPrincipalInfo();
|
||||
const mozilla::ipc::NullPrincipalInfo& pInfo =
|
||||
aPrincipalInfo.get_NullPrincipalInfo();
|
||||
|
||||
return spInfo.spec() == pInfo.spec() &&
|
||||
spInfo.attrs().EqualsIgnoringPartitionKey(pInfo.attrs());
|
||||
}
|
||||
|
||||
if (aPartitionedPrincipalInfo.type() ==
|
||||
mozilla::ipc::PrincipalInfo::TExpandedPrincipalInfo) {
|
||||
const mozilla::ipc::ExpandedPrincipalInfo& spInfo =
|
||||
aPartitionedPrincipalInfo.get_ExpandedPrincipalInfo();
|
||||
const mozilla::ipc::ExpandedPrincipalInfo& pInfo =
|
||||
aPrincipalInfo.get_ExpandedPrincipalInfo();
|
||||
|
||||
if (!spInfo.attrs().EqualsIgnoringPartitionKey(pInfo.attrs())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (spInfo.allowlist().Length() != pInfo.allowlist().Length()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < spInfo.allowlist().Length(); ++i) {
|
||||
if (!VerifyValidPartitionedPrincipalInfoForPrincipalInfoInternal(
|
||||
spInfo.allowlist()[i], pInfo.allowlist()[i],
|
||||
aIgnoreSpecForContentPrincipal,
|
||||
aIgnoreDomainForContentPrincipal)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_CRASH("Invalid principalInfo type");
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
|
@ -157,73 +229,18 @@ StoragePrincipalHelper::PrepareEffectiveStoragePrincipalOriginAttributes(
|
|||
|
||||
// static
|
||||
bool StoragePrincipalHelper::VerifyValidStoragePrincipalInfoForPrincipalInfo(
|
||||
const mozilla::ipc::PrincipalInfo& aStoragePrincipalInfo,
|
||||
const mozilla::ipc::PrincipalInfo& aPartitionedPrincipalInfo,
|
||||
const mozilla::ipc::PrincipalInfo& aPrincipalInfo) {
|
||||
if (aStoragePrincipalInfo.type() != aPrincipalInfo.type()) {
|
||||
return false;
|
||||
}
|
||||
return VerifyValidPartitionedPrincipalInfoForPrincipalInfoInternal(
|
||||
aPartitionedPrincipalInfo, aPrincipalInfo, false, false);
|
||||
}
|
||||
|
||||
if (aStoragePrincipalInfo.type() ==
|
||||
mozilla::ipc::PrincipalInfo::TContentPrincipalInfo) {
|
||||
const mozilla::ipc::ContentPrincipalInfo& spInfo =
|
||||
aStoragePrincipalInfo.get_ContentPrincipalInfo();
|
||||
const mozilla::ipc::ContentPrincipalInfo& pInfo =
|
||||
aPrincipalInfo.get_ContentPrincipalInfo();
|
||||
|
||||
if (!spInfo.attrs().EqualsIgnoringFPD(pInfo.attrs()) ||
|
||||
spInfo.originNoSuffix() != pInfo.originNoSuffix() ||
|
||||
spInfo.spec() != pInfo.spec() || spInfo.domain() != pInfo.domain() ||
|
||||
spInfo.baseDomain() != pInfo.baseDomain()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aStoragePrincipalInfo.type() ==
|
||||
mozilla::ipc::PrincipalInfo::TSystemPrincipalInfo) {
|
||||
// Nothing to check here.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aStoragePrincipalInfo.type() ==
|
||||
mozilla::ipc::PrincipalInfo::TNullPrincipalInfo) {
|
||||
const mozilla::ipc::NullPrincipalInfo& spInfo =
|
||||
aStoragePrincipalInfo.get_NullPrincipalInfo();
|
||||
const mozilla::ipc::NullPrincipalInfo& pInfo =
|
||||
aPrincipalInfo.get_NullPrincipalInfo();
|
||||
|
||||
return spInfo.spec() == pInfo.spec() &&
|
||||
spInfo.attrs().EqualsIgnoringFPD(pInfo.attrs());
|
||||
}
|
||||
|
||||
if (aStoragePrincipalInfo.type() ==
|
||||
mozilla::ipc::PrincipalInfo::TExpandedPrincipalInfo) {
|
||||
const mozilla::ipc::ExpandedPrincipalInfo& spInfo =
|
||||
aStoragePrincipalInfo.get_ExpandedPrincipalInfo();
|
||||
const mozilla::ipc::ExpandedPrincipalInfo& pInfo =
|
||||
aPrincipalInfo.get_ExpandedPrincipalInfo();
|
||||
|
||||
if (!spInfo.attrs().EqualsIgnoringFPD(pInfo.attrs())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (spInfo.allowlist().Length() != pInfo.allowlist().Length()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < spInfo.allowlist().Length(); ++i) {
|
||||
if (!VerifyValidStoragePrincipalInfoForPrincipalInfo(
|
||||
spInfo.allowlist()[i], pInfo.allowlist()[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_CRASH("Invalid principalInfo type");
|
||||
return false;
|
||||
// static
|
||||
bool StoragePrincipalHelper::VerifyValidClientPrincipalInfoForPrincipalInfo(
|
||||
const mozilla::ipc::PrincipalInfo& aClientPrincipalInfo,
|
||||
const mozilla::ipc::PrincipalInfo& aPrincipalInfo) {
|
||||
return VerifyValidPartitionedPrincipalInfoForPrincipalInfoInternal(
|
||||
aClientPrincipalInfo, aPrincipalInfo, true, true);
|
||||
}
|
||||
|
||||
// static
|
||||
|
|
|
@ -243,10 +243,19 @@ class StoragePrincipalHelper final {
|
|||
static nsresult PrepareEffectiveStoragePrincipalOriginAttributes(
|
||||
nsIChannel* aChannel, OriginAttributes& aOriginAttributes);
|
||||
|
||||
// A helper function to verify storage principal info with the principal info.
|
||||
static bool VerifyValidStoragePrincipalInfoForPrincipalInfo(
|
||||
const mozilla::ipc::PrincipalInfo& aStoragePrincipalInfo,
|
||||
const mozilla::ipc::PrincipalInfo& aPrincipalInfo);
|
||||
|
||||
// A helper function to verify client principal info with the principal info.
|
||||
//
|
||||
// Note that the client principal refers the principal of the client, which is
|
||||
// supposed to be the foreign partitioned principal.
|
||||
static bool VerifyValidClientPrincipalInfoForPrincipalInfo(
|
||||
const mozilla::ipc::PrincipalInfo& aClientPrincipalInfo,
|
||||
const mozilla::ipc::PrincipalInfo& aPrincipalInfo);
|
||||
|
||||
enum PrincipalType {
|
||||
// This is the first-party principal.
|
||||
eRegularPrincipal,
|
||||
|
@ -308,7 +317,7 @@ class StoragePrincipalHelper final {
|
|||
|
||||
// These methods return the correct originAttributes to be used for network
|
||||
// state components (HSTS, network cache, image-cache, and so on).
|
||||
static bool GetOriginAttributesForNetworkState(nsIChannel* aChanel,
|
||||
static bool GetOriginAttributesForNetworkState(nsIChannel* aChannel,
|
||||
OriginAttributes& aAttributes);
|
||||
static void GetOriginAttributesForNetworkState(dom::Document* aDocument,
|
||||
OriginAttributes& aAttributes);
|
||||
|
|
Загрузка…
Ссылка в новой задаче