Skip to content

Commit 0b87e0c

Browse files
committed
Bug 1885949 - Do not copy over HTTPS-First upgrade flag into new loadinfo r=necko-reviewers,freddyb,simonf,jesup
Differential Revision: https://phabricator.services.mozilla.com/D205048
1 parent 154791c commit 0b87e0c

File tree

8 files changed

+102
-3
lines changed

8 files changed

+102
-3
lines changed

dom/base/Document.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@
200200
#include "mozilla/dom/NetErrorInfoBinding.h"
201201
#include "mozilla/dom/NodeInfo.h"
202202
#include "mozilla/dom/NodeIterator.h"
203+
#include "mozilla/dom/nsHTTPSOnlyUtils.h"
203204
#include "mozilla/dom/PContentChild.h"
204205
#include "mozilla/dom/PWindowGlobalChild.h"
205206
#include "mozilla/dom/PageTransitionEvent.h"

dom/security/nsHTTPSOnlyUtils.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -902,6 +902,13 @@ bool nsHTTPSOnlyUtils::IsEqualURIExceptSchemeAndRef(nsIURI* aHTTPSSchemeURI,
902902

903903
return uriEquals;
904904
}
905+
906+
/* static */
907+
uint32_t nsHTTPSOnlyUtils::GetStatusForSubresourceLoad(
908+
uint32_t aHttpsOnlyStatus) {
909+
return aHttpsOnlyStatus & ~nsILoadInfo::HTTPS_ONLY_UPGRADED_HTTPS_FIRST;
910+
}
911+
905912
/////////////////////////////////////////////////////////////////////
906913
// Implementation of TestHTTPAnswerRunnable
907914

dom/security/nsHTTPSOnlyUtils.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,18 @@ class nsHTTPSOnlyUtils {
164164
nsIURI* aOtherURI,
165165
nsILoadInfo* aLoadInfo);
166166

167+
/**
168+
* Determines which HTTPS-Only status flags should get propagated to
169+
* sub-resources or sub-documents. As sub-resources and sub-documents are
170+
* exempt when the top-level document is exempt, we need to copy the "exempt"
171+
* flag. The HTTPS-First "upgraded" flag should not be copied to prevent a
172+
* unwanted downgrade (Bug 1885949).
173+
* @param aHttpsOnlyStatus The HTTPS-Only status of the top-level document.
174+
* @return The HTTPS-Only status that the sub-resource/document should
175+
* receive.
176+
*/
177+
static uint32_t GetStatusForSubresourceLoad(uint32_t aHttpsOnlyStatus);
178+
167179
private:
168180
/**
169181
* Checks if it can be ruled out that the error has something

dom/security/test/https-first/browser.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ support-files = [
4040
["browser_navigation.js"]
4141
support-files = ["file_navigation.html"]
4242

43+
["browser_subdocument_downgrade.js"]
44+
support-files = [
45+
"file_empty.html",
46+
"file_subdocument_downgrade.sjs",
47+
]
48+
4349
["browser_schemeless.js"]
4450

4551
["browser_slow_download.js"]
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/* Any copyright is dedicated to the Public Domain.
2+
https://creativecommons.org/publicdomain/zero/1.0/ */
3+
4+
"use strict";
5+
6+
const EMPTY_URL =
7+
"http://example.com/browser/dom/security/test/https-first/file_empty.html";
8+
const SUBDOCUMENT_URL =
9+
"https://example.com/browser/dom/security/test/https-first/file_subdocument_downgrade.sjs";
10+
11+
add_task(async function test_subdocument_downgrade() {
12+
await SpecialPowers.pushPrefEnv({
13+
set: [
14+
// We want to test HTTPS-First
15+
["dom.security.https_first", true],
16+
// Makes it easier to detect the error
17+
["security.mixed_content.block_active_content", false],
18+
],
19+
});
20+
21+
// Open a empty document with origin http://example.com, which gets upgraded
22+
// to https://example.com by HTTPS-First and thus is marked as
23+
// HTTPS_ONLY_UPGRADED_HTTPS_FIRST.
24+
await BrowserTestUtils.withNewTab(EMPTY_URL, async browser => {
25+
await SpecialPowers.spawn(
26+
browser,
27+
[SUBDOCUMENT_URL],
28+
async SUBDOCUMENT_URL => {
29+
function isCrossOriginIframe(iframe) {
30+
try {
31+
return !iframe.contentDocument;
32+
} catch (e) {
33+
return true;
34+
}
35+
}
36+
const subdocument = content.document.createElement("iframe");
37+
// We open https://example.com/.../file_subdocument_downgrade.sjs in a
38+
// iframe, which sends a invalid response if the scheme is https. Thus
39+
// we should get an error. But if we accidentally copy the
40+
// HTTPS_ONLY_UPGRADED_HTTPS_FIRST flag from the parent into the iframe
41+
// loadinfo, HTTPS-First will try to downgrade the iframe. We test that
42+
// this doesn't happen.
43+
subdocument.src = SUBDOCUMENT_URL;
44+
const loadPromise = new Promise(resolve => {
45+
subdocument.addEventListener("load", () => {
46+
ok(
47+
// If the iframe got downgraded, it should now have the origin
48+
// http://example.com, which we can detect as being cross-origin.
49+
!isCrossOriginIframe(subdocument),
50+
"Subdocument should not be downgraded"
51+
);
52+
resolve();
53+
});
54+
});
55+
content.document.body.appendChild(subdocument);
56+
await loadPromise;
57+
}
58+
);
59+
});
60+
});
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<!doctype html><html><body></body></html>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
function handleRequest(request, response) {
2+
if (request.scheme === "https") {
3+
response.setStatusLine("1.1", 429, "Too Many Requests");
4+
} else {
5+
response.setHeader("Content-Type", "text/html", false);
6+
response.write("<!doctype html><html><body></body></html>");
7+
}
8+
}

netwerk/base/LoadInfo.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "mozilla/dom/ToJSValue.h"
2121
#include "mozilla/dom/BrowsingContext.h"
2222
#include "mozilla/dom/WindowGlobalParent.h"
23+
#include "mozilla/dom/nsHTTPSOnlyUtils.h"
2324
#include "mozilla/net/CookieJarSettings.h"
2425
#include "mozilla/NullPrincipal.h"
2526
#include "mozilla/StaticPrefs_network.h"
@@ -216,8 +217,9 @@ LoadInfo::LoadInfo(
216217
mDocumentHasUserInteracted =
217218
aLoadingContext->OwnerDoc()->UserHasInteracted();
218219

219-
// Inherit HTTPS-Only Mode flags from parent document
220-
mHttpsOnlyStatus |= aLoadingContext->OwnerDoc()->HttpsOnlyStatus();
220+
// Inherit HTTPS-Only Mode flags from parent document.
221+
mHttpsOnlyStatus |= nsHTTPSOnlyUtils::GetStatusForSubresourceLoad(
222+
aLoadingContext->OwnerDoc()->HttpsOnlyStatus());
221223

222224
// When the element being loaded is a frame, we choose the frame's window
223225
// for the window ID and the frame element's window as the parent
@@ -528,7 +530,9 @@ LoadInfo::LoadInfo(dom::WindowGlobalParent* aParentWGP,
528530
parentBC->UsePrivateBrowsing());
529531
}
530532

531-
mHttpsOnlyStatus |= aParentWGP->HttpsOnlyStatus();
533+
// Inherit HTTPS-Only Mode flags from embedder document.
534+
mHttpsOnlyStatus |= nsHTTPSOnlyUtils::GetStatusForSubresourceLoad(
535+
aParentWGP->HttpsOnlyStatus());
532536

533537
// For chrome BC, the mPrivateBrowsingId remains 0 even its
534538
// UsePrivateBrowsing() is true, so we only update the mPrivateBrowsingId in

0 commit comments

Comments
 (0)