browser_HSTS.js (9913B)
1 /* Any copyright is dedicated to the Public Domain. 2 * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 // Tests that HTTP Strict Transport Security (HSTS) headers are noted as appropriate. 7 8 // Register a cleanup function to clear all accumulated HSTS state when this 9 // test is done. 10 add_setup(async function register_cleanup() { 11 await SpecialPowers.pushPrefEnv({ 12 set: [["test.wait300msAfterTabSwitch", true]], 13 }); 14 15 registerCleanupFunction(() => { 16 let sss = Cc["@mozilla.org/ssservice;1"].getService( 17 Ci.nsISiteSecurityService 18 ); 19 sss.clearAll(); 20 }); 21 }); 22 23 // In the absense of HSTS information, no upgrade should happen. 24 add_task(async function test_no_hsts_information_no_upgrade() { 25 let httpUrl = 26 getRootDirectory(gTestPath).replace( 27 "chrome://mochitests/content", 28 "http://example.com" 29 ) + "some_content.html"; 30 await BrowserTestUtils.openNewForegroundTab(gBrowser, httpUrl); 31 Assert.equal(gBrowser.selectedBrowser.currentURI.scheme, "http"); 32 gBrowser.removeCurrentTab(); 33 }); 34 35 // Visit a secure site that sends an HSTS header to set up the rest of the 36 // test. 37 add_task(async function see_hsts_header() { 38 let setHstsUrl = 39 getRootDirectory(gTestPath).replace( 40 "chrome://mochitests/content", 41 "https://example.com" 42 ) + "hsts_headers.sjs"; 43 await BrowserTestUtils.openNewForegroundTab(gBrowser, setHstsUrl); 44 gBrowser.removeCurrentTab(); 45 }); 46 47 // Given a known HSTS host, future http navigations to that domain will be 48 // upgraded. 49 add_task(async function test_http_upgrade() { 50 let httpUrl = 51 getRootDirectory(gTestPath).replace( 52 "chrome://mochitests/content", 53 "http://example.com" 54 ) + "some_content.html"; 55 await BrowserTestUtils.openNewForegroundTab(gBrowser, httpUrl); 56 Assert.equal(gBrowser.selectedBrowser.currentURI.scheme, "https"); 57 gBrowser.removeCurrentTab(); 58 }); 59 60 // http navigations to unrelated hosts should not be upgraded. 61 add_task(async function test_unrelated_domain_no_upgrade() { 62 let differentHttpUrl = 63 getRootDirectory(gTestPath).replace( 64 "chrome://mochitests/content", 65 "http://example.org" 66 ) + "some_content.html"; 67 await BrowserTestUtils.openNewForegroundTab(gBrowser, differentHttpUrl); 68 Assert.equal(gBrowser.selectedBrowser.currentURI.scheme, "http"); 69 gBrowser.removeCurrentTab(); 70 }); 71 72 // http navigations in private contexts shouldn't use information from 73 // non-private contexts, so no upgrade should occur. 74 add_task(async function test_private_window_no_upgrade() { 75 await SpecialPowers.pushPrefEnv({ 76 set: [["dom.security.https_first_pbm", false]], 77 }); 78 let privateWindow = OpenBrowserWindow({ private: true }); 79 await BrowserTestUtils.firstBrowserLoaded(privateWindow, false); 80 let url = 81 getRootDirectory(gTestPath).replace( 82 "chrome://mochitests/content", 83 "http://example.com" 84 ) + "some_content.html"; 85 await BrowserTestUtils.openNewForegroundTab(privateWindow.gBrowser, url); 86 Assert.equal( 87 privateWindow.gBrowser.selectedBrowser.currentURI.scheme, 88 "http" 89 ); 90 privateWindow.gBrowser.removeCurrentTab(); 91 privateWindow.close(); 92 }); 93 94 // Since the header didn't specify "includeSubdomains", visiting a subdomain 95 // should not result in an upgrade. 96 add_task(async function test_subdomain_no_upgrade() { 97 let subdomainHttpUrl = 98 getRootDirectory(gTestPath).replace( 99 "chrome://mochitests/content", 100 "http://test1.example.com" 101 ) + "some_content.html"; 102 await BrowserTestUtils.openNewForegroundTab(gBrowser, subdomainHttpUrl); 103 Assert.equal(gBrowser.selectedBrowser.currentURI.scheme, "http"); 104 gBrowser.removeCurrentTab(); 105 }); 106 107 // Now visit a secure site that sends an HSTS header that also includes subdomains. 108 add_task(async function see_hsts_header_include_subdomains() { 109 let setHstsUrl = 110 getRootDirectory(gTestPath).replace( 111 "chrome://mochitests/content", 112 "https://example.com" 113 ) + "hsts_headers.sjs?includeSubdomains"; 114 await BrowserTestUtils.openNewForegroundTab(gBrowser, setHstsUrl); 115 gBrowser.removeCurrentTab(); 116 }); 117 118 // Now visiting a subdomain should result in an upgrade. 119 add_task(async function test_subdomain_upgrade() { 120 let subdomainHttpUrl = 121 getRootDirectory(gTestPath).replace( 122 "chrome://mochitests/content", 123 "http://test1.example.com" 124 ) + "some_content.html"; 125 await BrowserTestUtils.openNewForegroundTab(gBrowser, subdomainHttpUrl); 126 Assert.equal(gBrowser.selectedBrowser.currentURI.scheme, "https"); 127 gBrowser.removeCurrentTab(); 128 }); 129 130 // Visiting a subdomain with https should result in an https URL (this isn't an 131 // upgrade - this test is essentially a consistency check). 132 add_task(async function test_already_https() { 133 let subdomainHttpsUrl = 134 getRootDirectory(gTestPath).replace( 135 "chrome://mochitests/content", 136 "https://test2.example.com" 137 ) + "some_content.html"; 138 await BrowserTestUtils.openNewForegroundTab(gBrowser, subdomainHttpsUrl); 139 Assert.equal(gBrowser.selectedBrowser.currentURI.scheme, "https"); 140 gBrowser.removeCurrentTab(); 141 }); 142 143 // Test that subresources are upgraded. 144 add_task(async function test_iframe_upgrade() { 145 let framedUrl = 146 getRootDirectory(gTestPath).replace( 147 "chrome://mochitests/content", 148 "https://example.com" 149 ) + "some_content_framed.html"; 150 await BrowserTestUtils.openNewForegroundTab(gBrowser, framedUrl); 151 await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function () { 152 await ContentTaskUtils.waitForCondition(() => { 153 let frame = content.document.getElementById("frame"); 154 if (frame) { 155 return frame.baseURI.startsWith("https://"); 156 } 157 return false; 158 }); 159 }); 160 gBrowser.removeCurrentTab(); 161 }); 162 163 // Clear state. 164 add_task(async function clear_hsts_state() { 165 let sss = Cc["@mozilla.org/ssservice;1"].getService( 166 Ci.nsISiteSecurityService 167 ); 168 sss.clearAll(); 169 }); 170 171 // Make sure this test is valid. 172 add_task(async function test_no_hsts_information_no_upgrade_again() { 173 let httpUrl = 174 getRootDirectory(gTestPath).replace( 175 "chrome://mochitests/content", 176 "http://example.com" 177 ) + "some_content.html"; 178 await BrowserTestUtils.openNewForegroundTab(gBrowser, httpUrl); 179 Assert.equal(gBrowser.selectedBrowser.currentURI.scheme, "http"); 180 gBrowser.removeCurrentTab(); 181 }); 182 183 // Visit a site with an iframe that loads first-party content that sends an 184 // HSTS header. The header should be heeded because it's first-party. 185 add_task(async function see_hsts_header_in_framed_first_party_context() { 186 let framedUrl = 187 getRootDirectory(gTestPath).replace( 188 "chrome://mochitests/content", 189 "https://example.com" 190 ) + "hsts_headers_framed.html"; 191 await BrowserTestUtils.openNewForegroundTab(gBrowser, framedUrl); 192 await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function () { 193 await ContentTaskUtils.waitForCondition(() => { 194 return content.document.getElementById("done"); 195 }); 196 }); 197 gBrowser.removeCurrentTab(); 198 }); 199 200 // Check that the framed, first-party header was heeded. 201 add_task(async function test_http_upgrade_after_framed_first_party_header() { 202 let httpUrl = 203 getRootDirectory(gTestPath).replace( 204 "chrome://mochitests/content", 205 "http://example.com" 206 ) + "some_content.html"; 207 await BrowserTestUtils.openNewForegroundTab(gBrowser, httpUrl); 208 Assert.equal(gBrowser.selectedBrowser.currentURI.scheme, "https"); 209 gBrowser.removeCurrentTab(); 210 }); 211 212 // Visit a site with an iframe that loads third-party content that sends an 213 // HSTS header. The header should be ignored because it's third-party. 214 add_task(async function see_hsts_header_in_third_party_context() { 215 let framedUrl = 216 getRootDirectory(gTestPath).replace( 217 "chrome://mochitests/content", 218 "https://example.com" 219 ) + "hsts_headers_framed.html?third-party"; 220 await BrowserTestUtils.openNewForegroundTab(gBrowser, framedUrl); 221 await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function () { 222 await ContentTaskUtils.waitForCondition(() => { 223 return content.document.getElementById("done"); 224 }); 225 }); 226 gBrowser.removeCurrentTab(); 227 }); 228 229 // Since the HSTS header was not received in a first-party context, no upgrade 230 // should occur. 231 add_task(async function test_no_upgrade_for_third_party_header() { 232 let url = 233 getRootDirectory(gTestPath).replace( 234 "chrome://mochitests/content", 235 "http://example.org" 236 ) + "some_content.html"; 237 await BrowserTestUtils.openNewForegroundTab(gBrowser, url); 238 Assert.equal(gBrowser.selectedBrowser.currentURI.scheme, "http"); 239 gBrowser.removeCurrentTab(); 240 }); 241 242 // Clear state again. 243 add_task(async function clear_hsts_state_again() { 244 let sss = Cc["@mozilla.org/ssservice;1"].getService( 245 Ci.nsISiteSecurityService 246 ); 247 sss.clearAll(); 248 }); 249 250 // HSTS information encountered in private contexts should not be used in 251 // non-private contexts. 252 add_task( 253 async function test_no_upgrade_for_HSTS_information_from_private_window() { 254 await SpecialPowers.pushPrefEnv({ 255 set: [["dom.security.https_first_pbm", false]], 256 }); 257 let privateWindow = OpenBrowserWindow({ private: true }); 258 await BrowserTestUtils.firstBrowserLoaded(privateWindow, false); 259 let setHstsUrl = 260 getRootDirectory(gTestPath).replace( 261 "chrome://mochitests/content", 262 "https://example.com" 263 ) + "hsts_headers.sjs"; 264 await BrowserTestUtils.openNewForegroundTab( 265 privateWindow.gBrowser, 266 setHstsUrl 267 ); 268 privateWindow.gBrowser.removeCurrentTab(); 269 270 let httpUrl = 271 getRootDirectory(gTestPath).replace( 272 "chrome://mochitests/content", 273 "http://example.com" 274 ) + "some_content.html"; 275 await BrowserTestUtils.openNewForegroundTab(gBrowser, httpUrl); 276 Assert.equal(gBrowser.selectedBrowser.currentURI.scheme, "http"); 277 gBrowser.removeCurrentTab(); 278 279 privateWindow.close(); 280 } 281 );