tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 );