diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /dom/security/test/referrer-policy/browser_referrer_disallow_cross_site_relaxing.js | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/security/test/referrer-policy/browser_referrer_disallow_cross_site_relaxing.js')
-rw-r--r-- | dom/security/test/referrer-policy/browser_referrer_disallow_cross_site_relaxing.js | 458 |
1 files changed, 458 insertions, 0 deletions
diff --git a/dom/security/test/referrer-policy/browser_referrer_disallow_cross_site_relaxing.js b/dom/security/test/referrer-policy/browser_referrer_disallow_cross_site_relaxing.js new file mode 100644 index 0000000000..b77cac7365 --- /dev/null +++ b/dom/security/test/referrer-policy/browser_referrer_disallow_cross_site_relaxing.js @@ -0,0 +1,458 @@ +/** + * Bug 1720294 - Testing disallow relaxing default referrer policy for + * cross-site requests. + */ + +"use strict"; + +requestLongerTimeout(6); + +const TEST_DOMAIN = "https://example.com/"; +const TEST_SAME_SITE_DOMAIN = "https://test1.example.com/"; +const TEST_SAME_SITE_DOMAIN_HTTP = "http://test1.example.com/"; +const TEST_CROSS_SITE_DOMAIN = "https://test1.example.org/"; +const TEST_CROSS_SITE_DOMAIN_HTTP = "http://test1.example.org/"; + +const TEST_PATH = "browser/dom/security/test/referrer-policy/"; + +const TEST_PAGE = `${TEST_DOMAIN}${TEST_PATH}referrer_page.sjs`; +const TEST_SAME_SITE_PAGE = `${TEST_SAME_SITE_DOMAIN}${TEST_PATH}referrer_page.sjs`; +const TEST_SAME_SITE_PAGE_HTTP = `${TEST_SAME_SITE_DOMAIN_HTTP}${TEST_PATH}referrer_page.sjs`; +const TEST_CROSS_SITE_PAGE = `${TEST_CROSS_SITE_DOMAIN}${TEST_PATH}referrer_page.sjs`; +const TEST_CROSS_SITE_PAGE_HTTP = `${TEST_CROSS_SITE_DOMAIN_HTTP}${TEST_PATH}referrer_page.sjs`; + +const REFERRER_FULL = 0; +const REFERRER_ORIGIN = 1; +const REFERRER_NONE = 2; + +function getExpectedReferrer(referrer, type) { + let res; + + switch (type) { + case REFERRER_FULL: + res = referrer; + break; + case REFERRER_ORIGIN: + let url = new URL(referrer); + res = `${url.origin}/`; + break; + case REFERRER_NONE: + res = ""; + break; + default: + ok(false, "unknown type"); + } + + return res; +} + +async function verifyResultInPage(browser, expected) { + await SpecialPowers.spawn(browser, [expected], value => { + is(content.document.referrer, value, "The document.referrer is correct."); + + let result = content.document.getElementById("result"); + is(result.textContent, value, "The referer header is correct"); + }); +} + +function getExpectedConsoleMessage(expected, isPrefOn, url) { + let msg; + + if (isPrefOn) { + msg = + "Referrer Policy: Ignoring the less restricted referrer policy “" + + expected + + "” for the cross-site request: " + + url; + } else { + msg = + "Referrer Policy: Less restricted policies, including " + + "‘no-referrer-when-downgrade’, ‘origin-when-cross-origin’ and " + + "‘unsafe-url’, will be ignored soon for the cross-site request: " + + url; + } + + return msg; +} + +function createConsoleMessageVerificationPromise(expected, isPrefOn, url) { + if (!expected) { + return Promise.resolve(); + } + + return new Promise(resolve => { + let listener = { + observe(msg) { + let message = msg.QueryInterface(Ci.nsIScriptError); + + if (message.category.startsWith("Security")) { + is( + message.errorMessage, + getExpectedConsoleMessage(expected, isPrefOn, url), + "The console message is correct." + ); + Services.console.unregisterListener(listener); + resolve(); + } + }, + }; + + Services.console.registerListener(listener); + }); +} + +function verifyNoConsoleMessage() { + // Verify that there is no referrer policy console message. + let allMessages = Services.console.getMessageArray(); + + for (let msg of allMessages) { + let message = msg.QueryInterface(Ci.nsIScriptError); + if ( + message.category.startsWith("Security") && + message.errorMessage.startsWith("Referrer Policy:") + ) { + ok(false, "There should be no console message for referrer policy."); + } + } +} + +const TEST_CASES = [ + // Testing that the referrer policy can be overridden with less restricted + // policy in the same-origin scenario. + { + policy: "unsafe-url", + referrer: TEST_PAGE, + test_url: TEST_PAGE, + expect: REFERRER_FULL, + original: REFERRER_FULL, + }, + // Testing that the referrer policy can be overridden with less restricted + // policy in the same-site scenario. + { + policy: "unsafe-url", + referrer: TEST_PAGE, + test_url: TEST_SAME_SITE_PAGE, + expect: REFERRER_FULL, + original: REFERRER_FULL, + }, + { + policy: "no-referrer-when-downgrade", + referrer: TEST_PAGE, + test_url: TEST_SAME_SITE_PAGE, + expect: REFERRER_FULL, + original: REFERRER_FULL, + }, + { + policy: "origin-when-cross-origin", + referrer: TEST_PAGE, + test_url: TEST_SAME_SITE_PAGE_HTTP, + expect: REFERRER_ORIGIN, + original: REFERRER_ORIGIN, + }, + // Testing that the referrer policy cannot be overridden with less restricted + // policy in the cross-site scenario. + { + policy: "unsafe-url", + referrer: TEST_PAGE, + test_url: TEST_CROSS_SITE_PAGE, + expect: REFERRER_ORIGIN, + expect_console: "unsafe-url", + original: REFERRER_FULL, + }, + { + policy: "no-referrer-when-downgrade", + referrer: TEST_PAGE, + test_url: TEST_CROSS_SITE_PAGE, + expect: REFERRER_ORIGIN, + expect_console: "no-referrer-when-downgrade", + original: REFERRER_FULL, + }, + { + policy: "origin-when-cross-origin", + referrer: TEST_PAGE, + test_url: TEST_CROSS_SITE_PAGE_HTTP, + expect: REFERRER_NONE, + expect_console: "origin-when-cross-origin", + original: REFERRER_ORIGIN, + }, + // Testing that the referrer policy can still be overridden with more + // restricted policy in the cross-site scenario. + { + policy: "no-referrer", + referrer: TEST_PAGE, + test_url: TEST_CROSS_SITE_PAGE, + expect: REFERRER_NONE, + original: REFERRER_NONE, + }, +]; + +add_setup(async function () { + await SpecialPowers.pushPrefEnv({ + set: [ + // Disable mixed content blocking to be able to test downgrade scenario. + ["security.mixed_content.block_active_content", false], + ], + }); +}); + +async function runTestIniFrame(gBrowser, enabled, expectNoConsole) { + await BrowserTestUtils.withNewTab( + { gBrowser, url: "about:blank" }, + async browser => { + for (let type of ["meta", "header"]) { + for (let test of TEST_CASES) { + info(`Test iframe: ${test.toSource()}`); + let referrerURL = `${test.referrer}?${type}=${test.policy}`; + let expected = enabled + ? getExpectedReferrer(referrerURL, test.expect) + : getExpectedReferrer(referrerURL, test.original); + + let expected_console = expectNoConsole + ? undefined + : test.expect_console; + + Services.console.reset(); + + BrowserTestUtils.loadURIString(browser, referrerURL); + await BrowserTestUtils.browserLoaded(browser, false, referrerURL); + + let iframeURL = test.test_url + "?show"; + + let consolePromise = createConsoleMessageVerificationPromise( + expected_console, + enabled, + iframeURL + ); + // Create an iframe and load the url. + let bc = await SpecialPowers.spawn( + browser, + [iframeURL], + async url => { + let iframe = content.document.createElement("iframe"); + let loadPromise = ContentTaskUtils.waitForEvent(iframe, "load"); + iframe.src = url; + content.document.body.appendChild(iframe); + + await loadPromise; + + return iframe.browsingContext; + } + ); + + await verifyResultInPage(bc, expected); + await consolePromise; + if (!expected_console) { + verifyNoConsoleMessage(); + } + } + } + } + ); +} + +async function runTestForLinkClick(gBrowser, enabled, expectNoConsole) { + await BrowserTestUtils.withNewTab( + { gBrowser, url: "about:blank" }, + async browser => { + for (let type of ["meta", "header"]) { + for (let test of TEST_CASES) { + info(`Test link click: ${test.toSource()}`); + let referrerURL = `${test.referrer}?${type}=${test.policy}`; + let expected = enabled + ? getExpectedReferrer(referrerURL, test.expect) + : getExpectedReferrer(referrerURL, test.original); + + let expected_console = expectNoConsole + ? undefined + : test.expect_console; + + Services.console.reset(); + + BrowserTestUtils.loadURIString(browser, referrerURL); + await BrowserTestUtils.browserLoaded(browser, false, referrerURL); + + let linkURL = test.test_url + "?show"; + + let consolePromise = createConsoleMessageVerificationPromise( + expected_console, + enabled, + linkURL + ); + + // Create the promise to wait for the navigation finishes. + let loadedPromise = BrowserTestUtils.browserLoaded( + browser, + false, + linkURL + ); + + // Generate the link and click it to navigate. + await SpecialPowers.spawn(browser, [linkURL], async url => { + let link = content.document.createElement("a"); + link.textContent = "Link"; + link.setAttribute("href", url); + + content.document.body.appendChild(link); + link.click(); + }); + + await loadedPromise; + + await verifyResultInPage(browser, expected); + await consolePromise; + if (!expected_console) { + verifyNoConsoleMessage(); + } + } + } + } + ); +} + +async function toggleETPForPage(gBrowser, url, toggle) { + let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url); + + // First, Toggle ETP off for the test page. + let browserLoadedPromise = BrowserTestUtils.browserLoaded( + tab.linkedBrowser, + false, + url + ); + + if (toggle) { + gProtectionsHandler.enableForCurrentPage(); + } else { + gProtectionsHandler.disableForCurrentPage(); + } + + await browserLoadedPromise; + BrowserTestUtils.removeTab(tab); +} + +add_task(async function test_iframe() { + for (let enabled of [true, false]) { + await SpecialPowers.pushPrefEnv({ + set: [["network.http.referer.disallowCrossSiteRelaxingDefault", enabled]], + }); + + await runTestIniFrame(gBrowser, enabled); + } +}); + +add_task(async function test_iframe_pbmode() { + let win = await BrowserTestUtils.openNewBrowserWindow({ private: true }); + + for (let enabled of [true, false]) { + await SpecialPowers.pushPrefEnv({ + set: [ + [ + "network.http.referer.disallowCrossSiteRelaxingDefault.pbmode", + enabled, + ], + ], + }); + + await runTestIniFrame(win.gBrowser, enabled); + } + + await BrowserTestUtils.closeWindow(win); +}); + +add_task(async function test_link_click() { + for (let enabled of [true, false]) { + for (let enabled_top of [true, false]) { + await SpecialPowers.pushPrefEnv({ + set: [ + ["network.http.referer.disallowCrossSiteRelaxingDefault", enabled], + [ + "network.http.referer.disallowCrossSiteRelaxingDefault.top_navigation", + enabled_top, + ], + ], + }); + + // We won't show the console message if the strict rule is disabled for + // the top navigation. + await runTestForLinkClick(gBrowser, enabled && enabled_top, !enabled_top); + } + } +}); + +add_task(async function test_link_click_pbmode() { + let win = await BrowserTestUtils.openNewBrowserWindow({ private: true }); + + for (let enabled of [true, false]) { + for (let enabled_top of [true, false]) { + await SpecialPowers.pushPrefEnv({ + set: [ + [ + "network.http.referer.disallowCrossSiteRelaxingDefault.pbmode", + enabled, + ], + [ + "network.http.referer.disallowCrossSiteRelaxingDefault.pbmode.top_navigation", + enabled_top, + ], + // Disable https first mode for private browsing mode to test downgrade + // cases. + ["dom.security.https_first_pbm", false], + ], + }); + + // We won't show the console message if the strict rule is disabled for + // the top navigation in the private browsing window. + await runTestForLinkClick( + win.gBrowser, + enabled && enabled_top, + !enabled_top + ); + } + } + + await BrowserTestUtils.closeWindow(win); +}); + +add_task(async function test_iframe_etp_toggle_off() { + await SpecialPowers.pushPrefEnv({ + set: [["network.http.referer.disallowCrossSiteRelaxingDefault", true]], + }); + + // Open a new tab for the test page and toggle ETP off. + await toggleETPForPage(gBrowser, TEST_PAGE, false); + + // Run the test to see if the protection is disabled. We won't send console + // message if the protection was disabled by the ETP toggle. + await runTestIniFrame(gBrowser, false, true); + + // toggle ETP on again. + await toggleETPForPage(gBrowser, TEST_PAGE, true); + + // Run the test again to see if the protection is enabled. + await runTestIniFrame(gBrowser, true); +}); + +add_task(async function test_link_click_etp_toggle_off() { + await SpecialPowers.pushPrefEnv({ + set: [ + ["network.http.referer.disallowCrossSiteRelaxingDefault", true], + [ + "network.http.referer.disallowCrossSiteRelaxingDefault.top_navigation", + true, + ], + ], + }); + + // Toggle ETP off for the cross site. Note that the cross site is the place + // where we test against the ETP permission for top navigation. + await toggleETPForPage(gBrowser, TEST_CROSS_SITE_PAGE, false); + + // Run the test to see if the protection is disabled. We won't send console + // message if the protection was disabled by the ETP toggle. + await runTestForLinkClick(gBrowser, false, true); + + // toggle ETP on again. + await toggleETPForPage(gBrowser, TEST_CROSS_SITE_PAGE, true); + + // Run the test again to see if the protection is enabled. + await runTestForLinkClick(gBrowser, true); +}); |