Bug 1922193 - Cleanup invalid first-party partitioned cookies in the cookie DB. r=valentin,cookie-reviewers,edgul

Depends on D226125

Differential Revision: https://phabricator.services.mozilla.com/D226126
This commit is contained in:
Tim Huang 2024-11-05 18:50:35 +00:00
parent 2da0932815
commit da988c20a5
3 changed files with 218 additions and 0 deletions

View File

@ -1826,6 +1826,21 @@ void CookiePersistentStorage::InitDBConn() {
// evicted.
RefPtr<Cookie> cookie =
Cookie::CreateValidated(*tuple.cookie, tuple.originAttributes);
// Clean up the invalid first-party partitioned cookies that don't have
// the 'partitioned' cookie attribution. This will also ensure that we don't
// read the cookie into memory.
if (CookieCommons::IsFirstPartyPartitionedCookieWithoutCHIPS(
cookie, tuple.key.mBaseDomain, tuple.key.mOriginAttributes)) {
// We cannot directly use the cookie after validation because the
// timestamps could be different from the cookies in DB. So, we need to
// create one from the cookie struct.
RefPtr<Cookie> invalidCookie =
Cookie::Create(*tuple.cookie, tuple.originAttributes);
cleanupCookies.AppendElement(invalidCookie);
continue;
}
AddCookieToList(tuple.key.mBaseDomain, tuple.key.mOriginAttributes, cookie);
}

View File

@ -0,0 +1,201 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// The test ensure we remove first-party partitioned cookies that don't have
// partitioned attribute.
add_task(async function run_test() {
// Set up a profile.
let profile = do_get_profile();
// Start the cookieservice, to force creation of a database.
Services.cookies.sessionCookies;
// Close the profile.
await promise_close_profile();
// Create a schema 14 database.
let schema14db = new CookieDatabaseConnection(
do_get_cookie_file(profile),
14
);
let now = Math.round(Date.now() / 1000);
// Create an invalid first-party partitioned cookie.
let invalidFPCookie = new Cookie(
"invalid",
"bad",
"example.com",
"/",
now + 34560000,
now,
now,
false, // isSession
true, // isSecure
false, // isHttpOnly
false, // isBrowserElement
{ partitionKey: "(https,example.com)" },
Ci.nsICookie.SAMESITE_NONE,
Ci.nsICookie.SAMESITE_NONE,
Ci.nsICookie.SCHEME_UNSET,
false // isPartitioned
);
schema14db.insertCookie(invalidFPCookie);
// Create a valid first-party partitioned cookie(CHIPS).
let valid1stCHIPS = new Cookie(
"valid1stCHIPS",
"good",
"example.com",
"/",
now + 34560000,
now,
now,
false, // isSession
true, // isSecure
false, // isHttpOnly
false, // isBrowserElement
{ partitionKey: "(https,example.com)" },
Ci.nsICookie.SAMESITE_NONE,
Ci.nsICookie.SAMESITE_NONE,
Ci.nsICookie.SCHEME_UNSET,
true // isPartitioned
);
schema14db.insertCookie(valid1stCHIPS);
// Create a valid unpartitioned cookie.
let unpartitionedCookie = new Cookie(
"valid",
"good",
"example.com",
"/",
now + 34560000,
now,
now,
false, // isSession
true, // isSecure
false, // isHttpOnly
false, // isBrowserElement
{},
Ci.nsICookie.SAMESITE_NONE,
Ci.nsICookie.SAMESITE_NONE,
Ci.nsICookie.SCHEME_UNSET,
false // isPartitioned
);
schema14db.insertCookie(unpartitionedCookie);
// Create valid third-party partitioned TCP cookie.
let valid3rdTCPCookie = new Cookie(
"valid3rdTCP",
"good",
"example.com",
"/",
now + 34560000,
now,
now,
false, // isSession
true, // isSecure
false, // isHttpOnly
false, // isBrowserElement
{ partitionKey: "(https,example.org)" },
Ci.nsICookie.SAMESITE_NONE,
Ci.nsICookie.SAMESITE_NONE,
Ci.nsICookie.SCHEME_UNSET,
false // isPartitioned
);
schema14db.insertCookie(valid3rdTCPCookie);
// Create valid third-party partitioned CHIPS cookie.
let valid3rdCHIPSCookie = new Cookie(
"valid3rdCHIPS",
"good",
"example.com",
"/",
now + 34560000,
now,
now,
false, // isSession
true, // isSecure
false, // isHttpOnly
false, // isBrowserElement
{ partitionKey: "(https,example.org)" },
Ci.nsICookie.SAMESITE_NONE,
Ci.nsICookie.SAMESITE_NONE,
Ci.nsICookie.SCHEME_UNSET,
true // isPartitioned
);
schema14db.insertCookie(valid3rdCHIPSCookie);
schema14db.close();
schema14db = null;
// Check if we have the right testing entries
{
const dbConnection = Services.storage.openDatabase(
do_get_cookie_file(profile)
);
const stmt = dbConnection.createStatement(
"SELECT count(name) FROM moz_cookies WHERE host = 'example.com';"
);
const success = stmt.executeStep();
Assert.ok(success);
const count = stmt.getInt32(0);
Assert.equal(count, 5);
stmt.finalize();
dbConnection.close();
}
// Reload profile.
await promise_load_profile();
// Check the number of unpartitioned cookies is correct, and we only have
// good cookies.
let cookies = Services.cookies.getCookiesFromHost("example.com", {});
Assert.equal(cookies.length, 1);
for (const cookie of cookies) {
Assert.equal(cookie.value, "good");
}
// Check the number of first-party partitioned cookies is correct, and we only
// have good cookies.
cookies = Services.cookies.getCookiesFromHost("example.com", {
partitionKey: "(https,example.com)",
});
Assert.equal(cookies.length, 1);
for (const cookie of cookies) {
Assert.equal(cookie.value, "good");
}
// Check the number of third-party partitioned cookies is correct, and we only
// have good cookies.
cookies = Services.cookies.getCookiesFromHost("example.com", {
partitionKey: "(https,example.org)",
});
Assert.equal(cookies.length, 2);
for (const cookie of cookies) {
Assert.equal(cookie.value, "good");
}
// Ensure the invalid cookies is gone in the DB.
{
const dbConnection = Services.storage.openDatabase(
do_get_cookie_file(profile)
);
const stmt = dbConnection.createStatement(
"SELECT count(name) FROM moz_cookies WHERE value = 'bad';"
);
const success = stmt.executeStep();
Assert.ok(success);
const count = stmt.getInt32(0);
Assert.equal(count, 0);
stmt.finalize();
dbConnection.close();
}
// Cleanup
Services.cookies.removeAll();
do_close_profile();
});

View File

@ -1069,6 +1069,8 @@ skip-if = [
["test_referrer_policy.js"]
["test_remove_invalid_first_party_partitioned_cookie.js"]
["test_reopen.js"]
["test_reply_without_content_type.js"]