forked from mirrors/gecko-dev
		
	Bug 1873626 - Restrict cookies with partitioned attribution to be used only in secure contexts. r=bvandersloot,cookie-reviewers,edgul
Differential Revision: https://phabricator.services.mozilla.com/D199231
This commit is contained in:
		
							parent
							
								
									57d845b1ad
								
							
						
					
					
						commit
						550505c7d8
					
				
					 4 changed files with 98 additions and 7 deletions
				
			
		|  | @ -1663,6 +1663,19 @@ bool CookieService::ParseAttributes(nsIConsoleReportCollector* aCRC, | ||||||
|                                 SAMESITE_MDN_URL}); |                                 SAMESITE_MDN_URL}); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   // Ensure the partitioned cookie is set with the secure attribute.
 | ||||||
|  |   if (aCookieData.isPartitioned() && !aCookieData.isSecure()) { | ||||||
|  |     CookieLogging::LogMessageToConsole( | ||||||
|  |         aCRC, aHostURI, nsIScriptError::errorFlag, CONSOLE_REJECTION_CATEGORY, | ||||||
|  |         "CookieRejectedPartitionedRequiresSecure"_ns, | ||||||
|  |         AutoTArray<nsString, 1>{NS_ConvertUTF8toUTF16(aCookieData.name())}); | ||||||
|  | 
 | ||||||
|  |     // We only drop the cookie if CHIPS is enabled.
 | ||||||
|  |     if (StaticPrefs::network_cookie_cookieBehavior_optInPartitioning()) { | ||||||
|  |       return newCookie; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   if (aCookieData.rawSameSite() == nsICookie::SAMESITE_NONE && |   if (aCookieData.rawSameSite() == nsICookie::SAMESITE_NONE && | ||||||
|       aCookieData.sameSite() == nsICookie::SAMESITE_LAX) { |       aCookieData.sameSite() == nsICookie::SAMESITE_LAX) { | ||||||
|     bool laxByDefault = |     bool laxByDefault = | ||||||
|  |  | ||||||
|  | @ -131,3 +131,71 @@ add_task(async _ => { | ||||||
|   // Let's close the tab.
 |   // Let's close the tab.
 | ||||||
|   BrowserTestUtils.removeTab(tab); |   BrowserTestUtils.removeTab(tab); | ||||||
| }); | }); | ||||||
|  | 
 | ||||||
|  | // Run the test with CHIPS enabled, ensuring the partitioned cookies require
 | ||||||
|  | // secure context.
 | ||||||
|  | add_task(async function partitionedAttrRequiresSecure() { | ||||||
|  |   await SpecialPowers.pushPrefEnv({ | ||||||
|  |     set: [["network.cookie.cookieBehavior.optInPartitioning", true]], | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   // Clear all cookies before testing.
 | ||||||
|  |   Services.cookies.removeAll(); | ||||||
|  | 
 | ||||||
|  |   const expected = []; | ||||||
|  | 
 | ||||||
|  |   const consoleListener = { | ||||||
|  |     observe(what) { | ||||||
|  |       if (!(what instanceof Ci.nsIConsoleMessage)) { | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       info("Console Listener: " + what); | ||||||
|  |       for (let i = expected.length - 1; i >= 0; --i) { | ||||||
|  |         const e = expected[i]; | ||||||
|  | 
 | ||||||
|  |         if (what.message.includes(e.match)) { | ||||||
|  |           ok(true, "Message received: " + e.match); | ||||||
|  |           expected.splice(i, 1); | ||||||
|  |           e.resolve(); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   Services.console.registerListener(consoleListener); | ||||||
|  | 
 | ||||||
|  |   registerCleanupFunction(() => | ||||||
|  |     Services.console.unregisterListener(consoleListener) | ||||||
|  |   ); | ||||||
|  | 
 | ||||||
|  |   const netPromises = [ | ||||||
|  |     new Promise(resolve => { | ||||||
|  |       expected.push({ | ||||||
|  |         resolve, | ||||||
|  |         match: | ||||||
|  |           "Cookie “c” has been rejected because it has the “Partitioned” attribute but is missing the “secure” attribute.", | ||||||
|  |       }); | ||||||
|  |     }), | ||||||
|  |   ]; | ||||||
|  | 
 | ||||||
|  |   // Let's open our tab.
 | ||||||
|  |   const tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TOP_PAGE); | ||||||
|  | 
 | ||||||
|  |   // Set cookies with cross-site HTTP
 | ||||||
|  |   await SpecialPowers.spawn(tab.linkedBrowser, [], async function () { | ||||||
|  |     await content.fetch( | ||||||
|  |       "https://example.org/browser/netwerk/cookie/test/browser/partitioned.sjs?nosecure", | ||||||
|  |       { credentials: "include" } | ||||||
|  |     ); | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   // Let's wait for the first set of console events.
 | ||||||
|  |   await Promise.all(netPromises); | ||||||
|  | 
 | ||||||
|  |   // Ensure no cookie is set.
 | ||||||
|  |   is(Services.cookies.cookies.length, 0, "No cookie is set."); | ||||||
|  | 
 | ||||||
|  |   // Let's close the tab.
 | ||||||
|  |   BrowserTestUtils.removeTab(tab); | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | @ -13,12 +13,20 @@ function handleRequest(aRequest, aResponse) { | ||||||
|     aResponse.setStatusLine(aRequest.httpVersion, 200); |     aResponse.setStatusLine(aRequest.httpVersion, 200); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   if (!params.has("nocookie")) { |   if (params.has("nocookie")) { | ||||||
|     aResponse.setHeader("Set-Cookie", "a=1; SameSite=None; Secure", true); |     return; | ||||||
|     aResponse.setHeader( |  | ||||||
|       "Set-Cookie", |  | ||||||
|       "b=2; Partitioned; SameSite=None; Secure", |  | ||||||
|       true |  | ||||||
|     ); |  | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   if (params.has("nosecure")) { | ||||||
|  |     aResponse.setHeader("Set-Cookie", "c=3; Partitioned;", true); | ||||||
|  | 
 | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   aResponse.setHeader("Set-Cookie", "a=1; SameSite=None; Secure", true); | ||||||
|  |   aResponse.setHeader( | ||||||
|  |     "Set-Cookie", | ||||||
|  |     "b=2; Partitioned; SameSite=None; Secure", | ||||||
|  |     true | ||||||
|  |   ); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -86,6 +86,8 @@ CookieRejectedThirdParty=Cookie “%1$S” has been rejected as third-party. | ||||||
| CookieRejectedNonsecureOverSecure=Cookie “%1$S” has been rejected because there is an existing “secure” cookie. | CookieRejectedNonsecureOverSecure=Cookie “%1$S” has been rejected because there is an existing “secure” cookie. | ||||||
| # LOCALIZATION NOTE (CookieRejectedForNonSameSiteness): %1$S is the cookie name. | # LOCALIZATION NOTE (CookieRejectedForNonSameSiteness): %1$S is the cookie name. | ||||||
| CookieRejectedForNonSameSiteness=Cookie “%1$S” has been rejected because it is in a cross-site context and its “SameSite” is “Lax” or “Strict”. | CookieRejectedForNonSameSiteness=Cookie “%1$S” has been rejected because it is in a cross-site context and its “SameSite” is “Lax” or “Strict”. | ||||||
|  | # LOCALIZATION NOTE (CookieRejectedPartitionedRequiresSecure): %1$S is the cookie name. | ||||||
|  | CookieRejectedPartitionedRequiresSecure=Cookie “%1$S” has been rejected because it has the “Partitioned” attribute but is missing the “secure” attribute. | ||||||
| 
 | 
 | ||||||
| # LOCALIZATION NOTE (CookieForeignNoPartitionedWarning): %1$S is the cookie name. Do not translate "Partitioned" | # LOCALIZATION NOTE (CookieForeignNoPartitionedWarning): %1$S is the cookie name. Do not translate "Partitioned" | ||||||
| CookieForeignNoPartitionedWarning=Cookie “%1$S” will soon be rejected because it is foreign and does not have the “Partitioned“ attribute. | CookieForeignNoPartitionedWarning=Cookie “%1$S” will soon be rejected because it is foreign and does not have the “Partitioned“ attribute. | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Tim Huang
						Tim Huang