browser_hsts_host.js (6179B)
1 // Bug 1722489 - HTTPS-Only Mode - Tests evaluation order 2 // https://bugzilla.mozilla.org/show_bug.cgi?id=1722489 3 // This test ensures that an http request to an hsts host 4 // gets upgraded by hsts and not by https-only. 5 "use strict"; 6 7 // Set bools to track that tests ended. 8 let readMessage = false; 9 let testFinished = false; 10 // Visit a secure site that sends an HSTS header to set up the rest of the 11 // test. 12 add_task(async function see_hsts_header() { 13 let setHstsUrl = 14 getRootDirectory(gTestPath).replace( 15 "chrome://mochitests/content", 16 "https://example.com" 17 ) + "hsts_headers.sjs"; 18 Services.obs.addObserver(observer, "http-on-examine-response"); 19 20 let promiseLoaded = BrowserTestUtils.browserLoaded( 21 gBrowser.selectedBrowser, 22 false, 23 setHstsUrl 24 ); 25 BrowserTestUtils.startLoadingURIString(gBrowser.selectedBrowser, setHstsUrl); 26 await promiseLoaded; 27 28 await BrowserTestUtils.waitForCondition(() => readMessage); 29 // Clean up 30 Services.obs.removeObserver(observer, "http-on-examine-response"); 31 }); 32 33 // Test that HTTPS_Only is not performed if HSTS host is visited. 34 add_task(async function () { 35 // A longer timeout is necessary for this test than the plain mochitests 36 // due to opening a new tab with the web console. 37 requestLongerTimeout(4); 38 39 // Enable HTTPS-Only Mode and register console-listener 40 await SpecialPowers.pushPrefEnv({ 41 set: [["dom.security.https_only_mode", true]], 42 }); 43 44 Services.console.registerListener(onNewMessage); 45 const RESOURCE_LINK = 46 getRootDirectory(gTestPath).replace( 47 "chrome://mochitests/content", 48 "http://example.com" 49 ) + "hsts_headers.sjs"; 50 51 // 1. Upgrade page to https:// 52 let promiseLoaded = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); 53 BrowserTestUtils.startLoadingURIString( 54 gBrowser.selectedBrowser, 55 RESOURCE_LINK 56 ); 57 await promiseLoaded; 58 59 await BrowserTestUtils.waitForCondition(() => testFinished); 60 61 // Clean up 62 Services.console.unregisterListener(onNewMessage); 63 64 await SpecialPowers.popPrefEnv(); 65 }); 66 67 // Test that when clicking on #fragment with a different scheme (http vs https) 68 // DOES cause an actual navigation with HSTS, even though https-only mode is 69 // enabled. 70 add_task(async function () { 71 await SpecialPowers.pushPrefEnv({ 72 set: [ 73 ["dom.security.https_only_mode", true], 74 [ 75 "dom.security.https_only_mode_break_upgrade_downgrade_endless_loop", 76 false, 77 ], 78 ], 79 }); 80 81 const TEST_PAGE = 82 "http://example.com/browser/dom/security/test/https-only/file_fragment_noscript.html"; 83 84 await BrowserTestUtils.withNewTab( 85 { 86 gBrowser, 87 url: TEST_PAGE, 88 waitForLoad: true, 89 }, 90 async function (browser) { 91 const UPGRADED_URL = TEST_PAGE.replace("http:", "https:"); 92 93 await SpecialPowers.spawn(browser, [UPGRADED_URL], async function (url) { 94 is(content.window.location.href, url); 95 96 content.window.addEventListener("scroll", () => { 97 ok(false, "scroll event should not trigger"); 98 }); 99 100 let beforeUnload = new Promise(resolve => { 101 content.window.addEventListener("beforeunload", resolve, { 102 once: true, 103 }); 104 }); 105 106 content.window.document.querySelector("#clickMeButton").click(); 107 108 // Wait for unload event. 109 await beforeUnload; 110 }); 111 112 await BrowserTestUtils.browserLoaded(browser); 113 114 await SpecialPowers.spawn(browser, [UPGRADED_URL], async function (url) { 115 is(content.window.location.href, url + "#foo"); 116 }); 117 } 118 ); 119 120 await SpecialPowers.popPrefEnv(); 121 }); 122 123 add_task(async function () { 124 // Reset HSTS header 125 readMessage = false; 126 let clearHstsUrl = 127 getRootDirectory(gTestPath).replace( 128 "chrome://mochitests/content", 129 "https://example.com" 130 ) + "hsts_headers.sjs?reset"; 131 132 Services.obs.addObserver(observer, "http-on-examine-response"); 133 // reset hsts header 134 let promiseLoaded = BrowserTestUtils.browserLoaded( 135 gBrowser.selectedBrowser, 136 false, 137 clearHstsUrl 138 ); 139 await BrowserTestUtils.startLoadingURIString( 140 gBrowser.selectedBrowser, 141 clearHstsUrl 142 ); 143 await promiseLoaded; 144 await BrowserTestUtils.waitForCondition(() => readMessage); 145 // Clean up 146 Services.obs.removeObserver(observer, "http-on-examine-response"); 147 }); 148 149 function observer(subject, topic) { 150 info("observer called with " + topic); 151 if (topic == "http-on-examine-response") { 152 onExamineResponse(subject); 153 } 154 } 155 156 function onExamineResponse(subject) { 157 let channel = subject.QueryInterface(Ci.nsIHttpChannel); 158 // If message was already read or is not related to "example.com", 159 // don't examine it. 160 if (!channel.URI.spec.includes("example.com") || readMessage) { 161 return; 162 } 163 info("onExamineResponse with " + channel.URI.spec); 164 if (channel.URI.spec.includes("reset")) { 165 try { 166 let hsts = channel.getResponseHeader("Strict-Transport-Security"); 167 is(hsts, "max-age=0", "HSTS header is not set"); 168 } catch (e) { 169 ok(false, "HSTS header still set"); 170 } 171 readMessage = true; 172 return; 173 } 174 try { 175 let hsts = channel.getResponseHeader("Strict-Transport-Security"); 176 let csp = channel.getResponseHeader("Content-Security-Policy"); 177 // Check that HSTS and CSP upgrade headers are set 178 is(hsts, "max-age=60", "HSTS header is set"); 179 is(csp, "upgrade-insecure-requests", "CSP header is set"); 180 } catch (e) { 181 ok(false, "No header set"); 182 } 183 readMessage = true; 184 } 185 186 function onNewMessage(msgObj) { 187 const message = msgObj.message; 188 // ensure that request is not upgraded HTTPS-Only. 189 if (message.includes("Upgrading insecure request")) { 190 ok(false, "Top-Level upgrade shouldn't get logged"); 191 testFinished = true; 192 } else if ( 193 message.includes("Upgrading insecure speculative TCP connection") 194 ) { 195 // TODO: Check assertion 196 // https://bugzilla.mozilla.org/show_bug.cgi?id=1735683 197 ok(true, "Top-Level upgrade shouldn't get logged"); 198 testFinished = true; 199 } else if (gBrowser.selectedBrowser.currentURI.scheme === "https") { 200 ok(true, "Top-Level upgrade shouldn't get logged"); 201 testFinished = true; 202 } 203 }