summaryrefslogtreecommitdiffstats
path: root/dom/security/test/csp/test_upgrade_insecure.html
blob: 0827b7f2df486577e82a927aa5f826ae89ac1c10 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
<!DOCTYPE HTML>
<html>
<head>
  <meta charset="utf-8">
  <title>Bug 1139297 - Implement CSP upgrade-insecure-requests directive</title>
  <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
  <script src="/tests/SimpleTest/SimpleTest.js"></script>
  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<iframe style="width:100%;" id="testframe"></iframe>

<script class="testbody" type="text/javascript">

/* Description of the test:
 * We load resources (img, script, sytle, etc) over *http* and make sure
 * that all the resources get upgraded to use  >> https << when the
 * csp-directive "upgrade-insecure-requests" is specified. We further
 * test that subresources within nested contexts (iframes) get upgraded
 * and also test the handling of server side redirects.
 *
 * In detail:
 * We perform an XHR request to the *.sjs file which is processed async on
 * the server and waits till all the requests were processed by the server.
 * Once the server received all the different requests, the server responds
 * to the initial XHR request with an array of results which must match
 * the expected results from each test, making sure that all requests
 * received by the server (*.sjs) were actually *https* requests.
 */

const { AppConstants } = SpecialPowers.ChromeUtils.importESModule(
  "resource://gre/modules/AppConstants.sys.mjs"
);

const UPGRADE_POLICY =
  "upgrade-insecure-requests;" +               // upgrade all http requests to https
  "block-all-mixed-content;" +                 // upgrade should be enforced before block-all.
  "default-src https: wss: 'unsafe-inline';" + // only allow https: and wss:
  "form-action https:;";                       // explicit, no fallback to default-src

const UPGRADE_POLICY_NO_DEFAULT_SRC =
  "upgrade-insecure-requests;" +               // upgrade all http requests to https
  "script-src 'unsafe-inline' *";              // we have to allowlist the inline scripts
                                               // in the test.
const NO_UPGRADE_POLICY =
  "default-src http: ws: 'unsafe-inline';" +   // allow http:// and ws://
  "form-action http:;";                        // explicit, no fallback to default-src

var tests = [
  { // (1) test that all requests within an >> https << page get updated
    policy: UPGRADE_POLICY,
    topLevelScheme: "https://",
    description: "upgrade all requests on toplevel https",
    deliveryMethod: "header",
    results: [
      "iframe-ok", "script-ok", "img-ok", "img-redir-ok", "font-ok", "xhr-ok", "style-ok",
      "media-ok", "object-ok", "form-ok", "nested-img-ok"
    ]
  },
  { // (2) test that all requests within an >> http << page get updated
    policy: UPGRADE_POLICY,
    topLevelScheme: "http://",
    description: "upgrade all requests on toplevel http",
    deliveryMethod: "header",
    results: [
      "iframe-ok", "script-ok", "img-ok", "img-redir-ok", "font-ok", "xhr-ok", "style-ok",
      "media-ok", "object-ok", "form-ok", "nested-img-ok"
    ]
  },
  { // (3) test that all requests within an >> http << page get updated, but do
    //     not specify a default-src directive.
    policy: UPGRADE_POLICY_NO_DEFAULT_SRC,
    topLevelScheme: "http://",
    description: "upgrade all requests on toplevel http where default-src is not specified",
    deliveryMethod: "header",
    results: [
      "iframe-ok", "script-ok", "img-ok", "img-redir-ok", "font-ok", "xhr-ok", "style-ok",
      "media-ok", "object-ok", "form-ok", "nested-img-ok"
    ]
  },
  { // (4) test that no requests get updated if >> upgrade-insecure-requests << is not used
    policy: NO_UPGRADE_POLICY,
    topLevelScheme: "http://",
    description: "do not upgrade any requests on toplevel http",
    deliveryMethod: "header",
    results: [
      "iframe-error", "script-error", "img-error", "img-redir-error", "font-error",
      "xhr-error", "style-error", "media-error", "object-error", "form-error",
      "nested-img-error"
    ]
  },
  { // (5) test that all requests within an >> https << page using meta CSP get updated
    // policy: UPGRADE_POLICY, that test uses UPGRADE_POLICY within
    //                         file_upgrade_insecure_meta.html
    //                         no need to define it within that object.
    topLevelScheme: "https://",
    description: "upgrade all requests on toplevel https using meta csp",
    deliveryMethod: "meta",
    results: [
      "iframe-ok", "script-ok", "img-ok", "img-redir-ok", "font-ok", "xhr-ok", "style-ok",
      "media-ok", "object-ok", "form-ok", "nested-img-ok"
    ]
  },
];

// TODO: WebSocket tests are not supported on Android Yet. Bug 1566168.
if (AppConstants.platform !== "android") {
    for (let test of tests) {
        test.results.push(test.results[0] == "iframe-ok" ? "websocket-ok" : "websocket-error");
    }
}

var counter = 0;
var curTest;

function loadTestPage() {
  curTest = tests[counter++];
  var src = curTest.topLevelScheme + "example.com/tests/dom/security/test/csp/file_testserver.sjs?file=";
  if (curTest.deliveryMethod === "header") {
    // append the file that should be served
    src += escape("tests/dom/security/test/csp/file_upgrade_insecure.html");
    // append the CSP that should be used to serve the file
    src += "&csp=" + escape(curTest.policy);
  }
  else {
    src += escape("tests/dom/security/test/csp/file_upgrade_insecure_meta.html");
    // no csp here, since it's in the meta element
  }
  document.getElementById("testframe").src = src;
}

function finishTest() {
  window.removeEventListener("message", receiveMessage);
  SimpleTest.finish();
}

function checkResults(result) {
    // try to find the expected result within the results array
  var index = curTest.results.indexOf(result);
  isnot(index, -1, curTest.description + " (result: " + result + ")");

  // take the element out the array and continue till the results array is empty
  if (index != -1) {
    curTest.results.splice(index, 1);
  }
  // lets check if we are expecting more results to bubble up
  if (curTest.results.length) {
    return;
  }
  // lets see if we ran all the tests
  if (counter == tests.length) {
    finishTest();
    return;
  }
  // otherwise it's time to run the next test
  runNextTest();
}

// a postMessage handler that is used by sandboxed iframes without
// 'allow-same-origin' to bubble up results back to this main page.
window.addEventListener("message", receiveMessage);
function receiveMessage(event) {
  checkResults(event.data.result);
}

function runNextTest() {
  // sends an xhr request to the server which is processed async, which only
  // returns after the server has received all the expected requests.
  var myXHR = new XMLHttpRequest();
  myXHR.open("GET", "file_upgrade_insecure_server.sjs?queryresult");
  myXHR.onload = function(e) {
    var results = myXHR.responseText.split(",");
    for (var index in results) {
      checkResults(results[index]);
    }
  }
  myXHR.onerror = function(e) {
    ok(false, "could not query results from server (" + e.message + ")");
    finishTest();
  }
  myXHR.send();

  // give it some time and run the testpage
  SimpleTest.executeSoon(loadTestPage);
}

SimpleTest.waitForExplicitFinish();
runNextTest();

</script>
</body>
</html>