Bug 1658924: Implement HTTPS-First and automatically fall back to http if secure top-level connection is not available r=necko-reviewers,JulianWels,mattwoodrow,dragana

Differential Revision: https://phabricator.services.mozilla.com/D111686
This commit is contained in:
Christoph Kerschbaumer 2021-04-13 17:43:12 +00:00
Родитель c3f86167b6
Коммит e1c35fda94
17 изменённых файлов: 393 добавлений и 32 удалений

Просмотреть файл

@ -305,6 +305,10 @@ https://127.0.0.3:433 privileged,cer
https://badcertdomain.example.com:82 privileged,cert=badCertDomain
https://mismatch.badcertdomain.example.com:443 privileged,cert=badCertDomain
# Hosts for HTTPS-First upgrades/downgrades
http://httpsfirst.com:80 privileged
https://httpsfirst.com:443 privileged,nocert
# Hosts for sha1 console warning tests
https://sha1ee.example.com:443 privileged,cert=sha1_end_entity
https://sha256ee.example.com:443 privileged,cert=sha256_end_entity

Просмотреть файл

@ -49,6 +49,7 @@ nsDocShellLoadState::nsDocShellLoadState(
mInheritPrincipal = aLoadState.InheritPrincipal();
mPrincipalIsExplicit = aLoadState.PrincipalIsExplicit();
mForceAllowDataURI = aLoadState.ForceAllowDataURI();
mIsExemptFromHTTPSOnlyMode = aLoadState.IsExemptFromHTTPSOnlyMode();
mOriginalFrameSrc = aLoadState.OriginalFrameSrc();
mIsFormSubmission = aLoadState.IsFormSubmission();
mLoadType = aLoadState.LoadType();
@ -103,6 +104,7 @@ nsDocShellLoadState::nsDocShellLoadState(const nsDocShellLoadState& aOther)
mPrincipalToInherit(aOther.mPrincipalToInherit),
mPartitionedPrincipalToInherit(aOther.mPartitionedPrincipalToInherit),
mForceAllowDataURI(aOther.mForceAllowDataURI),
mIsExemptFromHTTPSOnlyMode(aOther.mIsExemptFromHTTPSOnlyMode),
mOriginalFrameSrc(aOther.mOriginalFrameSrc),
mIsFormSubmission(aOther.mIsFormSubmission),
mLoadType(aOther.mLoadType),
@ -144,6 +146,7 @@ nsDocShellLoadState::nsDocShellLoadState(nsIURI* aURI, uint64_t aLoadIdentifier)
mPrincipalIsExplicit(false),
mNotifiedBeforeUnloadListeners(false),
mForceAllowDataURI(false),
mIsExemptFromHTTPSOnlyMode(false),
mOriginalFrameSrc(false),
mIsFormSubmission(false),
mLoadType(LOAD_NORMAL),
@ -486,6 +489,15 @@ void nsDocShellLoadState::SetForceAllowDataURI(bool aForceAllowDataURI) {
mForceAllowDataURI = aForceAllowDataURI;
}
bool nsDocShellLoadState::IsExemptFromHTTPSOnlyMode() const {
return mIsExemptFromHTTPSOnlyMode;
}
void nsDocShellLoadState::SetIsExemptFromHTTPSOnlyMode(
bool aIsExemptFromHTTPSOnlyMode) {
mIsExemptFromHTTPSOnlyMode = aIsExemptFromHTTPSOnlyMode;
}
bool nsDocShellLoadState::OriginalFrameSrc() const { return mOriginalFrameSrc; }
void nsDocShellLoadState::SetOriginalFrameSrc(bool aOriginalFrameSrc) {
@ -933,6 +945,7 @@ DocShellLoadStateInit nsDocShellLoadState::Serialize() {
loadState.InheritPrincipal() = mInheritPrincipal;
loadState.PrincipalIsExplicit() = mPrincipalIsExplicit;
loadState.ForceAllowDataURI() = mForceAllowDataURI;
loadState.IsExemptFromHTTPSOnlyMode() = mIsExemptFromHTTPSOnlyMode;
loadState.OriginalFrameSrc() = mOriginalFrameSrc;
loadState.IsFormSubmission() = mIsFormSubmission;
loadState.LoadType() = mLoadType;

Просмотреть файл

@ -131,6 +131,10 @@ class nsDocShellLoadState final {
void SetForceAllowDataURI(bool aForceAllowDataURI);
bool IsExemptFromHTTPSOnlyMode() const;
void SetIsExemptFromHTTPSOnlyMode(bool aIsExemptFromHTTPSOnlyMode);
bool OriginalFrameSrc() const;
void SetOriginalFrameSrc(bool aOriginalFrameSrc);
@ -404,6 +408,10 @@ class nsDocShellLoadState final {
// to a data URI will be allowed.
bool mForceAllowDataURI;
// If this attribute is true, then the top-level navigaion
// will be exempt from HTTPS-Only-Mode upgrades.
bool mIsExemptFromHTTPSOnlyMode;
// If this attribute is true, this load corresponds to a frame
// element loading its original src (or srcdoc) attribute.
bool mOriginalFrameSrc;

Просмотреть файл

@ -250,6 +250,7 @@ struct DocShellLoadStateInit
nsIPrincipal PrincipalToInherit;
nsIPrincipal PartitionedPrincipalToInherit;
bool ForceAllowDataURI;
bool IsExemptFromHTTPSOnlyMode;
bool OriginalFrameSrc;
bool IsFormSubmission;
uint32_t LoadType;

Просмотреть файл

@ -138,6 +138,8 @@ HTTPSOnlyUpgradeRequest = Upgrading insecure request “%1$S” to use “%2$S
HTTPSOnlyNoUpgradeException = Not upgrading insecure request “%1$S” because it is exempt.
# LOCALIZATION NOTE: %1$S is the URL of the failed request; %2$S is an error-code.
HTTPSOnlyFailedRequest = Upgrading insecure request “%1$S” failed. (%2$S)
# LOCALIZATION NOTE: %S is the URL of the failed request;
HTTPSOnlyFailedDowngradeAgain = Upgrading insecure request “%S” failed. Downgrading to “http” again.
# LOCALIZATION NOTE: %S is the URL of the blocked request;
IframeSandboxBlockedDownload = Download of “%S” was blocked because the triggering iframe has the sandbox flag set.

Просмотреть файл

@ -44,6 +44,11 @@ bool nsHTTPSOnlyUtils::IsHttpsOnlyModeEnabled(bool aFromPrivateWindow) {
return false;
}
/* static */
bool nsHTTPSOnlyUtils::IsHttpsFirstModeEnabled() {
return mozilla::StaticPrefs::dom_security_https_only_mode_https_first();
}
/* static */
void nsHTTPSOnlyUtils::PotentiallyFireHttpRequestToShortenTimout(
mozilla::net::DocumentLoadListener* aDocumentLoadListener) {
@ -62,8 +67,9 @@ void nsHTTPSOnlyUtils::PotentiallyFireHttpRequestToShortenTimout(
nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
bool isPrivateWin = loadInfo->GetOriginAttributes().mPrivateBrowsingId > 0;
// if https-only mode is not even enabled, then there is nothing to do here.
if (!IsHttpsOnlyModeEnabled(isPrivateWin)) {
// if neither HTTPS-Only nor HTTPS-First mode is enabled, then there is
// nothing to do here.
if (!IsHttpsOnlyModeEnabled(isPrivateWin) && !IsHttpsFirstModeEnabled()) {
return;
}
@ -213,7 +219,7 @@ bool nsHTTPSOnlyUtils::IsUpgradeDowngradeEndlessLoop(nsIURI* aURI,
nsILoadInfo* aLoadInfo) {
// 1. Check if the HTTPS-Only Mode is even enabled, before we do anything else
bool isPrivateWin = aLoadInfo->GetOriginAttributes().mPrivateBrowsingId > 0;
if (!IsHttpsOnlyModeEnabled(isPrivateWin)) {
if (!IsHttpsOnlyModeEnabled(isPrivateWin) && !IsHttpsFirstModeEnabled()) {
return false;
}
@ -286,6 +292,93 @@ bool nsHTTPSOnlyUtils::IsUpgradeDowngradeEndlessLoop(nsIURI* aURI,
return uriHost.Equals(triggeringHost);
}
/* static */
bool nsHTTPSOnlyUtils::ShouldUpgradeHttpsFirstRequest(nsIURI* aURI,
nsILoadInfo* aLoadInfo) {
// 1. Check if HTTPS-First Mode is enabled
if (!IsHttpsFirstModeEnabled()) {
return false;
}
// 2. HTTPS-First only upgrades top-level loads
if (aLoadInfo->GetExternalContentPolicyType() !=
ExtContentPolicy::TYPE_DOCUMENT) {
return false;
}
// 3. Don't upgrade if upgraded previously or exempt from upgrades
uint32_t httpsOnlyStatus = aLoadInfo->GetHttpsOnlyStatus();
if (httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_UPGRADED_HTTPS_FIRST ||
httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_EXEMPT) {
return false;
}
// We can upgrade the request - let's log to the console and set the status
// so we know that we upgraded the request.
MOZ_ASSERT(aURI->SchemeIs("http"), "how come the request is not 'http'?");
nsAutoCString scheme;
aURI->GetScheme(scheme);
scheme.AppendLiteral("s");
NS_ConvertUTF8toUTF16 reportSpec(aURI->GetSpecOrDefault());
NS_ConvertUTF8toUTF16 reportScheme(scheme);
AutoTArray<nsString, 2> params = {reportSpec, reportScheme};
nsHTTPSOnlyUtils::LogLocalizedString("HTTPSOnlyUpgradeRequest", params,
nsIScriptError::warningFlag, aLoadInfo,
aURI, true);
// Set flag so we know that we upgraded the request
httpsOnlyStatus |= nsILoadInfo::HTTPS_ONLY_UPGRADED_HTTPS_FIRST;
aLoadInfo->SetHttpsOnlyStatus(httpsOnlyStatus);
return true;
}
/* static */
already_AddRefed<nsIURI>
nsHTTPSOnlyUtils::PotentiallyDowngradeHttpsFirstRequest(nsIChannel* aChannel,
nsresult aError) {
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
uint32_t httpsOnlyStatus = loadInfo->GetHttpsOnlyStatus();
// Only downgrade if we this request was upgraded using HTTPS-First Mode
if (!(httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_UPGRADED_HTTPS_FIRST)) {
return nullptr;
}
// No matter if we're downgrading or not, the request failed so we need to
// inform the background request.
loadInfo->SetHttpsOnlyStatus(
httpsOnlyStatus | nsILoadInfo::HTTPS_ONLY_TOP_LEVEL_LOAD_IN_PROGRESS);
// We're only downgrading if it's possible that the error was
// caused by the upgrade.
if (HttpsUpgradeUnrelatedErrorCode(aError)) {
return nullptr;
}
nsCOMPtr<nsIURI> uri;
nsresult rv = aChannel->GetURI(getter_AddRefs(uri));
NS_ENSURE_SUCCESS(rv, nullptr);
// Only downgrade if the current scheme is HTTPS
if (!uri->SchemeIs("https")) {
return nullptr;
}
// Change the scheme to http
nsCOMPtr<nsIURI> newURI;
mozilla::Unused << NS_MutateURI(uri).SetScheme("http"_ns).Finalize(
getter_AddRefs(newURI));
// Log downgrade to console
NS_ConvertUTF8toUTF16 reportSpec(uri->GetSpecOrDefault());
AutoTArray<nsString, 1> params = {reportSpec};
nsHTTPSOnlyUtils::LogLocalizedString("HTTPSOnlyFailedDowngradeAgain", params,
nsIScriptError::warningFlag, loadInfo,
uri, true);
return newURI.forget();
}
/* static */
bool nsHTTPSOnlyUtils::CouldBeHttpsOnlyError(nsIChannel* aChannel,
nsresult aError) {
@ -311,14 +404,7 @@ bool nsHTTPSOnlyUtils::CouldBeHttpsOnlyError(nsIChannel* aChannel,
// If it's one of those errors, then most likely it's not a HTTPS-Only error
// (This list of errors is largely drawn from nsDocShell::DisplayLoadError())
return !(NS_ERROR_UNKNOWN_PROTOCOL == aError ||
NS_ERROR_FILE_NOT_FOUND == aError ||
NS_ERROR_FILE_ACCESS_DENIED == aError ||
NS_ERROR_UNKNOWN_HOST == aError || NS_ERROR_PHISHING_URI == aError ||
NS_ERROR_MALWARE_URI == aError || NS_ERROR_UNWANTED_URI == aError ||
NS_ERROR_HARMFUL_URI == aError ||
NS_ERROR_CONTENT_CRASHED == aError ||
NS_ERROR_FRAME_CRASHED == aError);
return !HttpsUpgradeUnrelatedErrorCode(aError);
}
/* static */
@ -391,23 +477,35 @@ bool nsHTTPSOnlyUtils::IsSafeToAcceptCORSOrMixedContent(
return nsHTTPSOnlyUtils::IsHttpsOnlyModeEnabled(isPrivateWin);
}
/* static */
bool nsHTTPSOnlyUtils::HttpsUpgradeUnrelatedErrorCode(nsresult aError) {
return NS_ERROR_UNKNOWN_PROTOCOL == aError ||
NS_ERROR_FILE_NOT_FOUND == aError ||
NS_ERROR_FILE_ACCESS_DENIED == aError ||
NS_ERROR_UNKNOWN_HOST == aError || NS_ERROR_PHISHING_URI == aError ||
NS_ERROR_MALWARE_URI == aError || NS_ERROR_UNWANTED_URI == aError ||
NS_ERROR_HARMFUL_URI == aError || NS_ERROR_CONTENT_CRASHED == aError ||
NS_ERROR_FRAME_CRASHED == aError;
}
/* ------ Logging ------ */
/* static */
void nsHTTPSOnlyUtils::LogLocalizedString(const char* aName,
const nsTArray<nsString>& aParams,
uint32_t aFlags,
nsILoadInfo* aLoadInfo,
nsIURI* aURI) {
nsILoadInfo* aLoadInfo, nsIURI* aURI,
bool aUseHttpsFirst) {
nsAutoString logMsg;
nsContentUtils::FormatLocalizedString(nsContentUtils::eSECURITY_PROPERTIES,
aName, aParams, logMsg);
LogMessage(logMsg, aFlags, aLoadInfo, aURI);
LogMessage(logMsg, aFlags, aLoadInfo, aURI, aUseHttpsFirst);
}
/* static */
void nsHTTPSOnlyUtils::LogMessage(const nsAString& aMessage, uint32_t aFlags,
nsILoadInfo* aLoadInfo, nsIURI* aURI) {
nsILoadInfo* aLoadInfo, nsIURI* aURI,
bool aUseHttpsFirst) {
// do not log to the console if the loadinfo says we should not!
uint32_t httpsOnlyStatus = aLoadInfo->GetHttpsOnlyStatus();
if (httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_DO_NOT_LOG_TO_CONSOLE) {
@ -416,11 +514,12 @@ void nsHTTPSOnlyUtils::LogMessage(const nsAString& aMessage, uint32_t aFlags,
// Prepending HTTPS-Only to the outgoing console message
nsString message;
message.AppendLiteral(u"HTTPS-Only Mode: ");
message.Append(aUseHttpsFirst ? u"HTTPS-First Mode: "_ns
: u"HTTPS-Only Mode: "_ns);
message.Append(aMessage);
// Allow for easy distinction in devtools code.
nsCString category("HTTPSOnly");
nsCString category(aUseHttpsFirst ? "HTTPSFirst" : "HTTPSOnly");
uint32_t innerWindowId = aLoadInfo->GetInnerWindowID();
if (innerWindowId > 0) {

Просмотреть файл

@ -14,12 +14,18 @@
class nsHTTPSOnlyUtils {
public:
/**
* Returns if HTTPSOnly-Mode preference is enabled
* Returns if HTTPS-Only Mode preference is enabled
* @param aFromPrivateWindow true if executing in private browsing mode
* @return true if HTTPS-Only Mode is enabled
*/
static bool IsHttpsOnlyModeEnabled(bool aFromPrivateWindow);
/**
* Returns if HTTPS-First Mode preference is enabled
* @return true if HTTPS-First Mode is enabled
*/
static bool IsHttpsFirstModeEnabled();
/**
* Potentially fires an http request for a top-level load (provided by
* aDocumentLoadListener) in the background to avoid long timeouts in case
@ -64,8 +70,29 @@ class nsHTTPSOnlyUtils {
nsILoadInfo* aLoadInfo);
/**
* Checks if the error code is on a block-list of codes that are probably not
* related to a HTTPS-Only Mode upgrade.
* Determines if a request should get upgraded because of the HTTPS-First
* mode. If true, the httpsOnlyStatus in LoadInfo gets updated and a message
* is logged in the console.
* @param aURI nsIURI of request
* @param aLoadInfo nsILoadInfo of request
* @return true if request should get upgraded
*/
static bool ShouldUpgradeHttpsFirstRequest(nsIURI* aURI,
nsILoadInfo* aLoadInfo);
/**
* Determines if the request was previously upgraded with HTTPS-First, creates
* a downgraded URI and logs to console.
* @param aError Error code
* @param aChannel Failed channel
* @return URI with http-scheme or nullptr
*/
static already_AddRefed<nsIURI> PotentiallyDowngradeHttpsFirstRequest(
nsIChannel* aChannel, nsresult aError);
/**
* Checks if the error code is on a block-list of codes that are probably
* not related to a HTTPS-Only Mode upgrade.
* @param aChannel The failed Channel.
* @param aError Error Code from Request
* @return false if error is not related to upgrade
@ -74,16 +101,18 @@ class nsHTTPSOnlyUtils {
/**
* Logs localized message to either content console or browser console
* @param aName Localization key
* @param aParams Localization parameters
* @param aFlags Logging Flag (see nsIScriptError)
* @param aLoadInfo The loadinfo of the request.
* @param [aURI] Optional: URI to log
* @param aName Localization key
* @param aParams Localization parameters
* @param aFlags Logging Flag (see nsIScriptError)
* @param aLoadInfo The loadinfo of the request.
* @param [aURI] Optional: URI to log
* @param [aUseHttpsFirst] Optional: Log using HTTPS-First (vs. HTTPS-Only)
*/
static void LogLocalizedString(const char* aName,
const nsTArray<nsString>& aParams,
uint32_t aFlags, nsILoadInfo* aLoadInfo,
nsIURI* aURI = nullptr);
nsIURI* aURI = nullptr,
bool aUseHttpsFirst = false);
/**
* Tests if the HTTPS-Only upgrade exception is set for a given principal.
@ -123,15 +152,24 @@ class nsHTTPSOnlyUtils {
nsILoadInfo* aLoadInfo);
private:
/**
* Checks if it can be ruled out that the error has something
* to do with an HTTPS upgrade.
* @param aError error code
* @return true if error is unrelated to the upgrade
*/
static bool HttpsUpgradeUnrelatedErrorCode(nsresult aError);
/**
* Logs localized message to either content console or browser console
* @param aMessage Message to log
* @param aFlags Logging Flag (see nsIScriptError)
* @param aLoadInfo The loadinfo of the request.
* @param [aURI] Optional: URI to log
* @param aMessage Message to log
* @param aFlags Logging Flag (see nsIScriptError)
* @param aLoadInfo The loadinfo of the request.
* @param [aURI] Optional: URI to log
* @param [aUseHttpsFirst] Optional: Log using HTTPS-First (vs. HTTPS-Only)
*/
static void LogMessage(const nsAString& aMessage, uint32_t aFlags,
nsILoadInfo* aLoadInfo, nsIURI* aURI = nullptr);
nsILoadInfo* aLoadInfo, nsIURI* aURI = nullptr,
bool aUseHttpsFirst = false);
/**
* Checks whether the URI ends with .onion

Просмотреть файл

@ -0,0 +1,5 @@
"use strict";
module.exports = {
extends: ["plugin:mozilla/browser-test"],
};

Просмотреть файл

@ -0,0 +1,4 @@
[browser_httpsfirst.js]
support-files =
file_httpsfirst_timeout_server.sjs
[browser_httpsfirst_console_logging.js]

Просмотреть файл

@ -0,0 +1,63 @@
"use strict";
const TEST_PATH_HTTP = getRootDirectory(gTestPath).replace(
"chrome://mochitests/content",
"http://example.com"
);
const TIMEOUT_PAGE_URI_HTTP =
TEST_PATH_HTTP + "file_httpsfirst_timeout_server.sjs";
async function runPrefTest(aURI, aDesc, aAssertURLStartsWith) {
await BrowserTestUtils.withNewTab("about:blank", async function(browser) {
const loaded = BrowserTestUtils.browserLoaded(browser, false, null, true);
BrowserTestUtils.loadURI(browser, aURI);
await loaded;
await ContentTask.spawn(browser, { aDesc, aAssertURLStartsWith }, function({
aDesc,
aAssertURLStartsWith,
}) {
ok(
content.document.location.href.startsWith(aAssertURLStartsWith),
aDesc
);
});
});
}
add_task(async function() {
await runPrefTest(
"http://example.com",
"HTTPS-First disabled; Should not upgrade",
"http://"
);
await SpecialPowers.pushPrefEnv({
set: [["dom.security.https_only_mode_https_first", true]],
});
await runPrefTest(
"http://example.com",
"Should upgrade upgradeable website",
"https://"
);
await runPrefTest(
"http://httpsfirst.com",
"Should downgrade after error.",
"http://"
);
await runPrefTest(
"http://domain.does.not.exist",
"Should not downgrade on dnsNotFound error.",
"https://"
);
await runPrefTest(
TIMEOUT_PAGE_URI_HTTP,
"Should downgrade after timeout.",
"http://"
);
});

Просмотреть файл

@ -0,0 +1,71 @@
// Bug 1658924 - HTTPS-First Mode - Tests for console logging
// https://bugzilla.mozilla.org/show_bug.cgi?id=1658924
// This test makes sure that the various console messages from the HTTPS-First
// mode get logged to the console.
"use strict";
// Test Cases
// description: Description of what the subtests expects.
// expectLogLevel: Expected log-level of a message.
// expectIncludes: Expected substrings the message should contain.
let tests = [
{
description: "Top-Level upgrade should get logged",
expectLogLevel: Ci.nsIConsoleMessage.warn,
expectIncludes: ["Upgrading insecure request", "to use", "httpsfirst.com"],
},
{
description: "Top-Level upgrade failure should get logged",
expectLogLevel: Ci.nsIConsoleMessage.warn,
expectIncludes: [
"Upgrading insecure request",
"failed",
"httpsfirst.com",
"Downgrading to",
],
},
];
add_task(async function() {
// A longer timeout is necessary for this test than the plain mochitests
// due to opening a new tab with the web console.
requestLongerTimeout(4);
// Enable HTTPS-First Mode and register console-listener
await SpecialPowers.pushPrefEnv({
set: [["dom.security.https_only_mode_https_first", true]],
});
Services.console.registerListener(on_new_message);
// 1. Upgrade page to https://
await BrowserTestUtils.loadURI(
gBrowser.selectedBrowser,
"http://httpsfirst.com"
);
await BrowserTestUtils.waitForCondition(() => tests.length === 0);
// Clean up
Services.console.unregisterListener(on_new_message);
});
function on_new_message(msgObj) {
const message = msgObj.message;
const logLevel = msgObj.logLevel;
if (message.includes("HTTPS-First Mode:")) {
for (let i = 0; i < tests.length; i++) {
const testCase = tests[i];
// Check if log-level matches
if (logLevel !== testCase.expectLogLevel) {
continue;
}
// Check if all substrings are included
if (testCase.expectIncludes.some(str => !message.includes(str))) {
continue;
}
ok(true, testCase.description);
tests.splice(i, 1);
break;
}
}
}

Просмотреть файл

@ -0,0 +1,15 @@
function handleRequest(request, response)
{
// avoid confusing cache behaviors
response.setHeader("Cache-Control", "no-cache", false);
if (request.scheme === "https") {
// Simulating a timeout by processing the https request
// async and *never* return anything!
response.processAsync();
return;
}
// we should never get here; just in case, return something unexpected
response.write("do'h");
}

Просмотреть файл

@ -34,6 +34,7 @@ BROWSER_CHROME_MANIFESTS += [
"cors/browser.ini",
"csp/browser.ini",
"general/browser.ini",
"https-first/browser.ini",
"https-only/browser.ini",
"mixedcontentblocker/browser.ini",
]

Просмотреть файл

@ -2931,6 +2931,13 @@
value: false
mirror: always
# If true, top-level request will get upgraded to HTTPS and
# downgraded again if the request failed.
- name: dom.security.https_only_mode_https_first
type: RelaxedAtomicBool
value: false
mirror: always
- name: dom.security.unexpected_system_load_telemetry_enabled
type: bool
value: true

Просмотреть файл

@ -470,6 +470,12 @@ interface nsILoadInfo : nsISupports
*/
const unsigned long HTTPS_ONLY_DO_NOT_LOG_TO_CONSOLE = (1 << 5);
/**
* This flag indicates that the request should not be logged to the
* console.
*/
const unsigned long HTTPS_ONLY_UPGRADED_HTTPS_FIRST = (1 << 6);
/**
* Upgrade state of HTTPS-Only Mode. The flag HTTPS_ONLY_EXEMPT can get
* set on requests that should be excempt from an upgrade.

Просмотреть файл

@ -2856,7 +2856,8 @@ nsresult NS_ShouldSecureUpgrade(
!nsMixedContentBlocker::IsPotentiallyTrustworthyLoopbackURL(aURI)) {
if (aLoadInfo) {
// Check if the request can get upgraded with the HTTPS-Only mode
if (nsHTTPSOnlyUtils::ShouldUpgradeRequest(aURI, aLoadInfo)) {
if (nsHTTPSOnlyUtils::ShouldUpgradeRequest(aURI, aLoadInfo) ||
nsHTTPSOnlyUtils::ShouldUpgradeHttpsFirstRequest(aURI, aLoadInfo)) {
aShouldUpgrade = true;
return NS_OK;
}

Просмотреть файл

@ -140,6 +140,12 @@ static auto CreateDocumentLoadInfo(CanonicalBrowsingContext* aBrowsingContext,
attrs, securityFlags, sandboxFlags);
}
if (aLoadState->IsExemptFromHTTPSOnlyMode()) {
uint32_t httpsOnlyStatus = loadInfo->GetHttpsOnlyStatus();
httpsOnlyStatus |= nsILoadInfo::HTTPS_ONLY_EXEMPT;
loadInfo->SetHttpsOnlyStatus(httpsOnlyStatus);
}
loadInfo->SetTriggeringSandboxFlags(aLoadState->TriggeringSandboxFlags());
loadInfo->SetHasValidUserGestureActivation(
aLoadState->HasValidUserGestureActivation());
@ -2159,6 +2165,17 @@ bool DocumentLoadListener::MaybeHandleLoadErrorWithURIFixup(nsresult aStatus) {
mLoadStateInternalLoadFlags &
nsDocShell::INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP,
bc->UsePrivateBrowsing(), true, getter_AddRefs(newPostData));
// If the request failed, the above attempt to fix it failed but it
// was upgraded using HTTPS-First, then let's check if we can downgrade
// the scheme to HTTP again.
bool isHTTPSFirstFixup = false;
if (NS_FAILED(aStatus) && !newURI) {
newURI = nsHTTPSOnlyUtils::PotentiallyDowngradeHttpsFirstRequest(mChannel,
aStatus);
isHTTPSFirstFixup = true;
}
if (!newURI) {
return false;
}
@ -2179,6 +2196,12 @@ bool DocumentLoadListener::MaybeHandleLoadErrorWithURIFixup(nsresult aStatus) {
loadState->SetPostDataStream(newPostData);
if (isHTTPSFirstFixup) {
// We have to exempt the load from HTTPS-First to prevent a
// upgrade-downgrade loop.
loadState->SetIsExemptFromHTTPSOnlyMode(true);
}
bc->LoadURI(loadState, false);
return true;
}