зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1731982 - Part 7: 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:
Родитель
49ced1a209
Коммит
c76e241df9
|
@ -3056,16 +3056,25 @@ 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;
|
||||
}
|
||||
|
||||
// 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.
|
||||
if (NS_WARN_IF(!StoragePrincipalHelper::
|
||||
VerifyValidStoragePrincipalInfoForPrincipalInfo(
|
||||
aStoragePrincipalInfo, aPrincipalInfo))) {
|
||||
VerifyValidPartitionedPrincipalInfoForPrincipalInfo(
|
||||
aStoragePrincipalInfo, aPrincipalInfo,
|
||||
aCheckClientPrincipal))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -3073,7 +3082,7 @@ bool VerifyPrincipalInfo(const PrincipalInfo& aPrincipalInfo,
|
|||
}
|
||||
|
||||
bool VerifyClientId(const Maybe<ContentParentId>& aContentParentId,
|
||||
const PrincipalInfo& aPrincipalInfo,
|
||||
const Maybe<PrincipalInfo>& aPrincipalInfo,
|
||||
const Maybe<nsID>& aClientId) {
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
|
@ -3082,9 +3091,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;
|
||||
}
|
||||
}
|
||||
|
@ -6114,8 +6127,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;
|
||||
}
|
||||
|
||||
|
@ -6133,14 +6146,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;
|
||||
}
|
||||
|
@ -6157,12 +6177,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;
|
||||
}
|
||||
|
@ -7782,8 +7810,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;
|
||||
}
|
||||
|
||||
|
|
|
@ -363,6 +363,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 +379,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 +936,7 @@ nsresult LSObject::EnsureDatabase() {
|
|||
LSRequestPrepareDatastoreParams params;
|
||||
params.commonParams() = commonParams;
|
||||
params.clientId() = mClientId;
|
||||
params.clientPrincipalInfo() = mClientPrincipalInfo;
|
||||
|
||||
LSRequestResponse response;
|
||||
|
||||
|
@ -992,6 +997,7 @@ nsresult LSObject::EnsureObserver() {
|
|||
params.principalInfo() = *mPrincipalInfo;
|
||||
params.storagePrincipalInfo() = *mStoragePrincipalInfo;
|
||||
params.clientId() = mClientId;
|
||||
params.clientPrincipalInfo() = mClientPrincipalInfo;
|
||||
|
||||
LSRequestResponse response;
|
||||
|
||||
|
|
|
@ -82,6 +82,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
|
||||
|
|
|
@ -155,23 +155,26 @@ StoragePrincipalHelper::PrepareEffectiveStoragePrincipalOriginAttributes(
|
|||
}
|
||||
|
||||
// static
|
||||
bool StoragePrincipalHelper::VerifyValidStoragePrincipalInfoForPrincipalInfo(
|
||||
const mozilla::ipc::PrincipalInfo& aStoragePrincipalInfo,
|
||||
const mozilla::ipc::PrincipalInfo& aPrincipalInfo) {
|
||||
if (aStoragePrincipalInfo.type() != aPrincipalInfo.type()) {
|
||||
bool StoragePrincipalHelper::
|
||||
VerifyValidPartitionedPrincipalInfoForPrincipalInfo(
|
||||
const mozilla::ipc::PrincipalInfo& aPartitionedPrincipalInfo,
|
||||
const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
|
||||
bool aIgnoreSpecForContentPrincipal) {
|
||||
if (aPartitionedPrincipalInfo.type() != aPrincipalInfo.type()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aStoragePrincipalInfo.type() ==
|
||||
if (aPartitionedPrincipalInfo.type() ==
|
||||
mozilla::ipc::PrincipalInfo::TContentPrincipalInfo) {
|
||||
const mozilla::ipc::ContentPrincipalInfo& spInfo =
|
||||
aStoragePrincipalInfo.get_ContentPrincipalInfo();
|
||||
aPartitionedPrincipalInfo.get_ContentPrincipalInfo();
|
||||
const mozilla::ipc::ContentPrincipalInfo& pInfo =
|
||||
aPrincipalInfo.get_ContentPrincipalInfo();
|
||||
|
||||
if (!spInfo.attrs().EqualsIgnoringFPD(pInfo.attrs()) ||
|
||||
if (!spInfo.attrs().EqualsIgnoringPartitionKey(pInfo.attrs()) ||
|
||||
spInfo.originNoSuffix() != pInfo.originNoSuffix() ||
|
||||
spInfo.spec() != pInfo.spec() || spInfo.domain() != pInfo.domain() ||
|
||||
(!aIgnoreSpecForContentPrincipal && spInfo.spec() != pInfo.spec()) ||
|
||||
spInfo.domain() != pInfo.domain() ||
|
||||
spInfo.baseDomain() != pInfo.baseDomain()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -179,31 +182,31 @@ bool StoragePrincipalHelper::VerifyValidStoragePrincipalInfoForPrincipalInfo(
|
|||
return true;
|
||||
}
|
||||
|
||||
if (aStoragePrincipalInfo.type() ==
|
||||
if (aPartitionedPrincipalInfo.type() ==
|
||||
mozilla::ipc::PrincipalInfo::TSystemPrincipalInfo) {
|
||||
// Nothing to check here.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aStoragePrincipalInfo.type() ==
|
||||
if (aPartitionedPrincipalInfo.type() ==
|
||||
mozilla::ipc::PrincipalInfo::TNullPrincipalInfo) {
|
||||
const mozilla::ipc::NullPrincipalInfo& spInfo =
|
||||
aStoragePrincipalInfo.get_NullPrincipalInfo();
|
||||
aPartitionedPrincipalInfo.get_NullPrincipalInfo();
|
||||
const mozilla::ipc::NullPrincipalInfo& pInfo =
|
||||
aPrincipalInfo.get_NullPrincipalInfo();
|
||||
|
||||
return spInfo.spec() == pInfo.spec() &&
|
||||
spInfo.attrs().EqualsIgnoringFPD(pInfo.attrs());
|
||||
spInfo.attrs().EqualsIgnoringPartitionKey(pInfo.attrs());
|
||||
}
|
||||
|
||||
if (aStoragePrincipalInfo.type() ==
|
||||
if (aPartitionedPrincipalInfo.type() ==
|
||||
mozilla::ipc::PrincipalInfo::TExpandedPrincipalInfo) {
|
||||
const mozilla::ipc::ExpandedPrincipalInfo& spInfo =
|
||||
aStoragePrincipalInfo.get_ExpandedPrincipalInfo();
|
||||
aPartitionedPrincipalInfo.get_ExpandedPrincipalInfo();
|
||||
const mozilla::ipc::ExpandedPrincipalInfo& pInfo =
|
||||
aPrincipalInfo.get_ExpandedPrincipalInfo();
|
||||
|
||||
if (!spInfo.attrs().EqualsIgnoringFPD(pInfo.attrs())) {
|
||||
if (!spInfo.attrs().EqualsIgnoringPartitionKey(pInfo.attrs())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -212,8 +215,9 @@ bool StoragePrincipalHelper::VerifyValidStoragePrincipalInfoForPrincipalInfo(
|
|||
}
|
||||
|
||||
for (uint32_t i = 0; i < spInfo.allowlist().Length(); ++i) {
|
||||
if (!VerifyValidStoragePrincipalInfoForPrincipalInfo(
|
||||
spInfo.allowlist()[i], pInfo.allowlist()[i])) {
|
||||
if (!VerifyValidPartitionedPrincipalInfoForPrincipalInfo(
|
||||
spInfo.allowlist()[i], pInfo.allowlist()[i],
|
||||
aIgnoreSpecForContentPrincipal)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -242,9 +242,10 @@ class StoragePrincipalHelper final {
|
|||
static nsresult PrepareEffectiveStoragePrincipalOriginAttributes(
|
||||
nsIChannel* aChannel, OriginAttributes& aOriginAttributes);
|
||||
|
||||
static bool VerifyValidStoragePrincipalInfoForPrincipalInfo(
|
||||
const mozilla::ipc::PrincipalInfo& aStoragePrincipalInfo,
|
||||
const mozilla::ipc::PrincipalInfo& aPrincipalInfo);
|
||||
static bool VerifyValidPartitionedPrincipalInfoForPrincipalInfo(
|
||||
const mozilla::ipc::PrincipalInfo& aPartitionedPrincipalInfo,
|
||||
const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
|
||||
bool aIgnoreSpecForContentPrincipal);
|
||||
|
||||
enum PrincipalType {
|
||||
// This is the first-party principal.
|
||||
|
|
Загрузка…
Ссылка в новой задаче