Bug 1896083 - Do not HTTPS-First upgrade hostnames that do not end with a known public suffix r=necko-reviewers,valentin,simonf,freddyb

Differential Revision: https://phabricator.services.mozilla.com/D211543
This commit is contained in:
Malte Juergens 2024-06-21 16:47:41 +00:00
parent 755a2db2fe
commit 3c4c1e8ba1
6 changed files with 64 additions and 3 deletions

View File

@ -321,6 +321,8 @@ https://www.badcertdomain2.example.com:443 privileged,cer
http://httpsfirst.com:80 privileged
https://httpsfirst.com:443 privileged,nocert
https://invalid.example.com:443 privileged,nocert
http://httpsfirst.local:80 privileged
https://httpsfirst.local:443 privileged,nocert
# Hosts for sha1 console warning tests
https://sha1ee.example.com:443 privileged,cert=sha1_end_entity

View File

@ -14,7 +14,7 @@
#include "mozilla/net/DNS.h"
#include "nsContentUtils.h"
#include "nsHTTPSOnlyUtils.h"
#include "nsIConsoleService.h"
#include "nsIEffectiveTLDService.h"
#include "nsIHttpChannel.h"
#include "nsIHttpChannelInternal.h"
#include "nsIHttpsOnlyModePermission.h"
@ -370,7 +370,8 @@ bool nsHTTPSOnlyUtils::ShouldUpgradeHttpsFirstRequest(nsIURI* aURI,
}
// 3. Check for general exceptions
if (OnionException(aURI) || LoopbackOrLocalException(aURI)) {
if (OnionException(aURI) || LoopbackOrLocalException(aURI) ||
UnknownPublicSuffixException(aURI)) {
return false;
}
@ -869,6 +870,19 @@ bool nsHTTPSOnlyUtils::LoopbackOrLocalException(nsIURI* aURI) {
return (!upgradeLocal && addr.IsIPAddrLocal());
}
/* static */
bool nsHTTPSOnlyUtils::UnknownPublicSuffixException(nsIURI* aURI) {
nsCOMPtr<nsIEffectiveTLDService> tldService =
do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
NS_ENSURE_TRUE(tldService, false);
bool hasKnownPublicSuffix;
nsresult rv = tldService->HasKnownPublicSuffix(aURI, &hasKnownPublicSuffix);
NS_ENSURE_SUCCESS(rv, false);
return !hasKnownPublicSuffix;
}
/* static */
bool nsHTTPSOnlyUtils::ShouldUpgradeConnection(nsILoadInfo* aLoadInfo) {
// Check if one of parameters is null then webpage can't be loaded yet

View File

@ -249,6 +249,14 @@ class nsHTTPSOnlyUtils {
* @return true if the URI is either loopback or local
*/
static bool LoopbackOrLocalException(nsIURI* aURI);
/**
* Checks whether the host of the URI ends with a suffix that is not in the
* public suffix list.
* @param aURI URI object
* @return true if the host of the URI ends with a unknown suffix
*/
static bool UnknownPublicSuffixException(nsIURI* aURI);
};
/**

View File

@ -57,4 +57,6 @@ support-files = [
["browser_superfluos_auth.js"]
["browser_tlds.js"]
["browser_upgrade_onion.js"]

View File

@ -81,7 +81,7 @@ add_task(async function () {
);
await runPrefTest(
"http://domain.does.not.exist",
"http://domain.does.not.exist.example.com",
"Should not downgrade on dnsNotFound error.",
"https://"
);

View File

@ -0,0 +1,35 @@
/* Any copyright is dedicated to the Public Domain.
https://creativecommons.org/publicdomain/zero/1.0/ */
/* eslint-disable @microsoft/sdl/no-insecure-url */
"use strict";
// Here we test that HTTPS-First only tries to upgrade known TLDs. In detail:
// httpsfirst.com -> Should try to upgrade, as .com isn a known TLD
// httpsfirst.local -> Should not try to ipgrade, as .local isn't a known TLD
// We do that by visiting URLs that are only available via HTTP and detect if a
// up- and downgrade happened through the existing Glean temetry.
// Also see Bug 1896083 for reference.
async function runTest(aURL, aExpectUpDowngrade) {
const initialDowngradeCount = Glean.httpsfirst.downgraded.testGetValue();
BrowserTestUtils.startLoadingURIString(gBrowser, aURL);
await BrowserTestUtils.browserLoaded(gBrowser, false, null, true);
is(
Glean.httpsfirst.downgraded.testGetValue(),
aExpectUpDowngrade ? initialDowngradeCount + 1 : initialDowngradeCount,
`${
aExpectUpDowngrade ? "A" : "No"
} up- and downgrade should have happened on ${aURL}`
);
}
add_task(async function test_tlds() {
await SpecialPowers.pushPrefEnv({
set: [["dom.security.https_first", true]],
});
await runTest("http://httpsfirst.com", true);
await runTest("http://httpsfirst.local", false);
await runTest("http://httpsfirst", false);
});