Bug 1638358 - Cookie Schemeful Same-Site - part 6 - console messages, r=mayhemer

Differential Revision: https://phabricator.services.mozilla.com/D75800
This commit is contained in:
Andrea Marchesini 2020-06-02 13:50:32 +00:00
Родитель 7ff3759ac3
Коммит 6254482164
20 изменённых файлов: 305 добавлений и 55 удалений

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

@ -16,6 +16,14 @@ const BASE_CORS_ERROR_URL_PARAMS = new URLSearchParams({
utm_campaign: "default",
});
registerCleanupFunction(async function() {
await new Promise(resolve => {
Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value =>
resolve()
);
});
});
add_task(async function() {
await pushPref("devtools.webconsole.filter.netxhr", true);

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

@ -100,6 +100,12 @@ add_task(async function() {
info("Running test #" + i);
await runTest(test, hud);
}
await new Promise(resolve => {
Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value =>
resolve()
);
});
});
async function runTest(test, hud) {

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

@ -8,6 +8,14 @@ const TEST_PATH =
"http://example.com/browser/devtools/client/webconsole/" + "test/browser/";
const TEST_URI = TEST_PATH + TEST_FILE;
registerCleanupFunction(async function() {
await new Promise(resolve => {
Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value =>
resolve()
);
});
});
add_task(async function task() {
await pushPref("devtools.webconsole.filter.net", false);
await pushPref("devtools.webconsole.filter.netxhr", true);

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

@ -8,6 +8,14 @@ const TEST_PATH =
"https://example.com/browser/devtools/client/webconsole/test/browser/";
const TEST_URI = TEST_PATH + TEST_FILE;
registerCleanupFunction(async function() {
await new Promise(resolve => {
Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value =>
resolve()
);
});
});
add_task(async function task() {
await pushPref("devtools.webconsole.filter.netxhr", true);
const hud = await openNewTabAndConsole(TEST_URI);

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

@ -10,6 +10,14 @@ const TEST_URI = TEST_PATH + TEST_FILE;
requestLongerTimeout(2);
registerCleanupFunction(async function() {
await new Promise(resolve => {
Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value =>
resolve()
);
});
});
pushPref("devtools.webconsole.filter.net", false);
pushPref("devtools.webconsole.filter.netxhr", true);

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

@ -17,9 +17,16 @@ const XHR_PREF = "devtools.webconsole.filter.netxhr";
Services.prefs.setBoolPref(NET_PREF, true);
Services.prefs.setBoolPref(XHR_PREF, true);
registerCleanupFunction(() => {
registerCleanupFunction(async () => {
Services.prefs.clearUserPref(NET_PREF);
Services.prefs.clearUserPref(XHR_PREF);
await new Promise(resolve => {
Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value =>
resolve()
);
});
});
add_task(async function task() {

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

@ -11,6 +11,14 @@ const TEST_FILE = "test-network-request.html";
const TEST_PATH =
"http://example.com/browser/devtools/client/webconsole/test/browser/";
registerCleanupFunction(async function() {
await new Promise(resolve => {
Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value =>
resolve()
);
});
});
add_task(async function task() {
await pushPref("devtools.target-switching.enabled", true);
await pushPref("devtools.webconsole.filter.net", true);

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

@ -10,6 +10,14 @@ const TEST_URI = TEST_PATH + TEST_FILE;
pushPref("devtools.webconsole.filter.netxhr", true);
registerCleanupFunction(async function() {
await new Promise(resolve => {
Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value =>
resolve()
);
});
});
add_task(async function task() {
const hud = await openNewTabAndConsole(TEST_URI);

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

@ -17,6 +17,14 @@ const LEARN_MORE_URI =
pushPref(NET_PREF, true);
pushPref(XHR_PREF, true);
registerCleanupFunction(async function() {
await new Promise(resolve => {
Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value =>
resolve()
);
});
});
add_task(async function task() {
const hud = await openNewTabAndConsole(TEST_URI);
@ -79,6 +87,12 @@ add_task(async function task() {
ok(true, "Console menu is opened");
}
}
await new Promise(resolve => {
Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value =>
resolve()
);
});
});
function getMouseEvents() {

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

@ -16,8 +16,14 @@ const TEST_PATH =
const NET_PREF = "devtools.webconsole.filter.net";
Services.prefs.setBoolPref(NET_PREF, true);
registerCleanupFunction(() => {
registerCleanupFunction(async () => {
Services.prefs.clearUserPref(NET_PREF);
await new Promise(resolve => {
Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value =>
resolve()
);
});
});
add_task(async function task() {

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

@ -15,8 +15,14 @@ const TEST_PATH =
const NET_PREF = "devtools.webconsole.filter.net";
Services.prefs.setBoolPref(NET_PREF, true);
registerCleanupFunction(() => {
registerCleanupFunction(async () => {
Services.prefs.clearUserPref(NET_PREF);
await new Promise(resolve => {
Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value =>
resolve()
);
});
});
add_task(async function() {

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

@ -31,8 +31,14 @@ const { UrlClassifierTestUtils } = ChromeUtils.import(
"resource://testing-common/UrlClassifierTestUtils.jsm"
);
registerCleanupFunction(function() {
registerCleanupFunction(async function() {
UrlClassifierTestUtils.cleanupTestTrackers();
await new Promise(resolve => {
Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value =>
resolve()
);
});
});
pushPref("devtools.webconsole.groupWarningMessages", false);

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

@ -5,6 +5,7 @@
#include "Cookie.h"
#include "CookieCommons.h"
#include "CookieLogging.h"
#include "CookieService.h"
#include "mozilla/ContentBlocking.h"
#include "mozilla/ConsoleReportCollector.h"
@ -18,6 +19,9 @@
#include "nsIEffectiveTLDService.h"
#include "nsScriptSecurityManager.h"
constexpr auto CONSOLE_SCHEMEFUL_CATEGORY =
NS_LITERAL_CSTRING("cookieSchemeful");
namespace mozilla {
using dom::Document;
@ -456,12 +460,11 @@ bool CookieCommons::ShouldIncludeCrossSiteCookieForDocument(Cookie* aCookie) {
return sameSiteAttr == nsICookie::SAMESITE_NONE;
}
// static
bool CookieCommons::MaybeCompareScheme(Cookie* aCookie,
nsICookie::schemeType aSchemeType) {
if (!StaticPrefs::network_cookie_sameSite_schemeful()) {
return true;
}
namespace {
bool MaybeCompareSchemeInternal(Cookie* aCookie,
nsICookie::schemeType aSchemeType) {
MOZ_ASSERT(aCookie);
// This is an old cookie without a scheme yet. Let's consider it valid.
if (aCookie->SchemeMap() == nsICookie::SCHEME_UNSET) {
@ -471,6 +474,54 @@ bool CookieCommons::MaybeCompareScheme(Cookie* aCookie,
return !!(aCookie->SchemeMap() & aSchemeType);
}
} // namespace
// static
bool CookieCommons::MaybeCompareSchemeWithLogging(
nsIConsoleReportCollector* aCRC, nsIURI* aHostURI, Cookie* aCookie,
nsICookie::schemeType aSchemeType) {
MOZ_ASSERT(aCookie);
MOZ_ASSERT(aHostURI);
if (MaybeCompareSchemeInternal(aCookie, aSchemeType)) {
return true;
}
nsAutoCString uri;
nsresult rv = aHostURI->GetSpec(uri);
if (NS_WARN_IF(NS_FAILED(rv))) {
return !StaticPrefs::network_cookie_sameSite_schemeful();
}
if (!StaticPrefs::network_cookie_sameSite_schemeful()) {
CookieLogging::LogMessageToConsole(
aCRC, aHostURI, nsIScriptError::warningFlag, CONSOLE_SCHEMEFUL_CATEGORY,
NS_LITERAL_CSTRING("CookieSchemefulRejectForBeta"),
AutoTArray<nsString, 2>{NS_ConvertUTF8toUTF16(aCookie->Name()),
NS_ConvertUTF8toUTF16(uri)});
return true;
}
CookieLogging::LogMessageToConsole(
aCRC, aHostURI, nsIScriptError::warningFlag, CONSOLE_SCHEMEFUL_CATEGORY,
NS_LITERAL_CSTRING("CookieSchemefulReject"),
AutoTArray<nsString, 2>{NS_ConvertUTF8toUTF16(aCookie->Name()),
NS_ConvertUTF8toUTF16(uri)});
return false;
}
// static
bool CookieCommons::MaybeCompareScheme(Cookie* aCookie,
nsICookie::schemeType aSchemeType) {
MOZ_ASSERT(aCookie);
if (!StaticPrefs::network_cookie_sameSite_schemeful()) {
return true;
}
return MaybeCompareSchemeInternal(aCookie, aSchemeType);
}
// static
nsICookie::schemeType CookieCommons::URIToSchemeType(nsIURI* aURI) {
MOZ_ASSERT(aURI);

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

@ -109,6 +109,10 @@ class CookieCommons final {
static bool ShouldIncludeCrossSiteCookieForDocument(Cookie* aCookie);
static bool MaybeCompareSchemeWithLogging(nsIConsoleReportCollector* aCRC,
nsIURI* aHostURI, Cookie* aCookie,
nsICookie::schemeType aSchemeType);
static bool MaybeCompareScheme(Cookie* aCookie,
nsICookie::schemeType aSchemeType);

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

@ -157,5 +157,28 @@ void CookieLogging::LogEvicted(Cookie* aCookie, const char* details) {
MOZ_LOG(gCookieLog, LogLevel::Debug, ("\n"));
}
// static
void CookieLogging::LogMessageToConsole(nsIConsoleReportCollector* aCRC,
nsIURI* aURI, uint32_t aErrorFlags,
const nsACString& aCategory,
const nsACString& aMsg,
const nsTArray<nsString>& aParams) {
MOZ_ASSERT(aURI);
if (!aCRC) {
return;
}
nsAutoCString uri;
nsresult rv = aURI->GetSpec(uri);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
aCRC->AddConsoleReport(aErrorFlags, aCategory,
nsContentUtils::eNECKO_PROPERTIES, uri, 0, 0, aMsg,
aParams);
}
} // namespace net
} // namespace mozilla

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

@ -9,6 +9,7 @@
#include "mozilla/Logging.h"
#include "nsString.h"
class nsIConsoleReportCollector;
class nsIURI;
namespace mozilla {
@ -50,6 +51,12 @@ class CookieLogging final {
static void LogCookie(Cookie* aCookie);
static void LogEvicted(Cookie* aCookie, const char* aDetails);
static void LogMessageToConsole(nsIConsoleReportCollector* aCRC, nsIURI* aURI,
uint32_t aErrorFlags,
const nsACString& aCategory,
const nsACString& aMsg,
const nsTArray<nsString>& aParams);
};
} // namespace net

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

@ -910,6 +910,8 @@ void CookieService::GetCookiesForURI(
!nsContentUtils::IsURIInPrefList(
aHostURI, "network.cookie.sameSite.laxByDefault.disabledHosts");
nsCOMPtr<nsIConsoleReportCollector> crc = do_QueryInterface(aChannel);
// iterate the cookies!
for (Cookie* cookie : *cookies) {
// check the host, since the base domain lookup is conservative.
@ -923,7 +925,8 @@ void CookieService::GetCookiesForURI(
}
// The scheme doesn't match.
if (!CookieCommons::MaybeCompareScheme(cookie, schemeType)) {
if (!CookieCommons::MaybeCompareSchemeWithLogging(crc, aHostURI, cookie,
schemeType)) {
continue;
}
@ -1042,9 +1045,9 @@ bool CookieService::CanSetCookie(
size.AppendInt(kMaxBytesPerCookie);
params.AppendElement(size);
LogMessageToConsole(aCRC, aHostURI, nsIScriptError::warningFlag,
CONSOLE_OVERSIZE_CATEGORY,
NS_LITERAL_CSTRING("CookieOversize"), params);
CookieLogging::LogMessageToConsole(
aCRC, aHostURI, nsIScriptError::warningFlag, CONSOLE_OVERSIZE_CATEGORY,
NS_LITERAL_CSTRING("CookieOversize"), params);
return newCookie;
}
@ -1366,7 +1369,7 @@ bool CookieService::ParseAttributes(nsIConsoleReportCollector* aCRC,
aCookieData.rawSameSite() = nsICookie::SAMESITE_NONE;
sameSiteSet = true;
} else {
LogMessageToConsole(
CookieLogging::LogMessageToConsole(
aCRC, aHostURI, nsIScriptError::infoFlag, CONSOLE_SAMESITE_CATEGORY,
NS_LITERAL_CSTRING("CookieSameSiteValueInvalid"),
AutoTArray<nsString, 1>{NS_ConvertUTF8toUTF16(aCookieData.name())});
@ -1386,7 +1389,7 @@ bool CookieService::ParseAttributes(nsIConsoleReportCollector* aCRC,
aCookieData.sameSite() == nsICookie::SAMESITE_NONE) {
if (laxByDefault &&
StaticPrefs::network_cookie_sameSite_noneRequiresSecure()) {
LogMessageToConsole(
CookieLogging::LogMessageToConsole(
aCRC, aHostURI, nsIScriptError::infoFlag, CONSOLE_SAMESITE_CATEGORY,
NS_LITERAL_CSTRING("CookieRejectedNonRequiresSecure"),
AutoTArray<nsString, 1>{NS_ConvertUTF8toUTF16(aCookieData.name())});
@ -1394,7 +1397,7 @@ bool CookieService::ParseAttributes(nsIConsoleReportCollector* aCRC,
}
// if sameSite=lax by default is disabled, we want to warn the user.
LogMessageToConsole(
CookieLogging::LogMessageToConsole(
aCRC, aHostURI, nsIScriptError::warningFlag, CONSOLE_SAMESITE_CATEGORY,
NS_LITERAL_CSTRING("CookieRejectedNonRequiresSecureForBeta"),
AutoTArray<nsString, 2>{NS_ConvertUTF8toUTF16(aCookieData.name()),
@ -1404,12 +1407,12 @@ bool CookieService::ParseAttributes(nsIConsoleReportCollector* aCRC,
if (aCookieData.rawSameSite() == nsICookie::SAMESITE_NONE &&
aCookieData.sameSite() == nsICookie::SAMESITE_LAX) {
if (laxByDefault) {
LogMessageToConsole(
CookieLogging::LogMessageToConsole(
aCRC, aHostURI, nsIScriptError::infoFlag, CONSOLE_SAMESITE_CATEGORY,
NS_LITERAL_CSTRING("CookieLaxForced"),
AutoTArray<nsString, 1>{NS_ConvertUTF8toUTF16(aCookieData.name())});
} else {
LogMessageToConsole(
CookieLogging::LogMessageToConsole(
aCRC, aHostURI, nsIScriptError::warningFlag,
CONSOLE_SAMESITE_CATEGORY,
NS_LITERAL_CSTRING("CookieLaxForcedForBeta"),
@ -1425,29 +1428,6 @@ bool CookieService::ParseAttributes(nsIConsoleReportCollector* aCRC,
return newCookie;
}
// static
void CookieService::LogMessageToConsole(nsIConsoleReportCollector* aCRC,
nsIURI* aURI, uint32_t aErrorFlags,
const nsACString& aCategory,
const nsACString& aMsg,
const nsTArray<nsString>& aParams) {
MOZ_ASSERT(aURI);
if (!aCRC) {
return;
}
nsAutoCString uri;
nsresult rv = aURI->GetSpec(uri);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
aCRC->AddConsoleReport(aErrorFlags, aCategory,
nsContentUtils::eNECKO_PROPERTIES, uri, 0, 0, aMsg,
aParams);
}
/******************************************************************************
* CookieService impl:
* private domain & permission compliance enforcement functions
@ -1738,9 +1718,9 @@ bool CookieService::CheckPath(CookieStruct& aCookieData,
size.AppendInt(kMaxBytesPerPath);
params.AppendElement(size);
LogMessageToConsole(aCRC, aHostURI, nsIScriptError::warningFlag,
CONSOLE_OVERSIZE_CATEGORY,
NS_LITERAL_CSTRING("CookiePathOversize"), params);
CookieLogging::LogMessageToConsole(
aCRC, aHostURI, nsIScriptError::warningFlag, CONSOLE_OVERSIZE_CATEGORY,
NS_LITERAL_CSTRING("CookiePathOversize"), params);
return false;
}

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

@ -145,12 +145,6 @@ class CookieService final : public nsICookieService,
nsresult RemoveCookiesFromExactHost(const nsACString& aHost,
const OriginAttributesPattern& aPattern);
static void LogMessageToConsole(nsIConsoleReportCollector* aCRC, nsIURI* aURI,
uint32_t aErrorFlags,
const nsACString& aCategory,
const nsACString& aMsg,
const nsTArray<nsString>& aParams);
// cached members.
nsCOMPtr<mozIThirdPartyUtil> mThirdPartyUtil;
nsCOMPtr<nsIEffectiveTLDService> mTLDService;

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

@ -16,6 +16,23 @@ function inChildProcess() {
return Services.appinfo.processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
}
const { CookieXPCShellUtils } = ChromeUtils.import(
"resource://testing-common/CookieXPCShellUtils.jsm"
);
let cookieXPCShellUtilsInitialized = false;
function maybeInitializeCookieXPCShellUtils() {
if (!cookieXPCShellUtilsInitialized) {
cookieXPCShellUtilsInitialized = true;
CookieXPCShellUtils.init(this);
CookieXPCShellUtils.createServer({ hosts: ["example.org"] });
}
}
// Don't pick up default permissions from profile.
Services.prefs.setCharPref("permissions.manager.defaultsUrl", "");
add_task(async _ => {
do_get_profile();
@ -80,6 +97,8 @@ add_task(async _ => {
add_task(async () => {
do_get_profile();
maybeInitializeCookieXPCShellUtils();
// Allow all cookies if the pref service is available in this process.
if (!inChildProcess()) {
Services.prefs.setBoolPref(
@ -97,7 +116,7 @@ add_task(async _ => {
info("Let's set a cookie from HTTP example.org");
let uri = NetUtil.newURI("http://example.org/");
let uri = NetUtil.newURI("https://example.org/");
let principal = Services.scriptSecurityManager.createContentPrincipal(
uri,
{}
@ -114,7 +133,7 @@ add_task(async _ => {
let cookies = Services.cookies.getCookieStringFromHttp(uri, channel);
Assert.equal(cookies, "a=b", "Cookies match");
uri = NetUtil.newURI("https://example.org/");
uri = NetUtil.newURI("http://example.org/");
principal = Services.scriptSecurityManager.createContentPrincipal(uri, {});
channel = NetUtil.newChannel({
uri,
@ -130,7 +149,7 @@ add_task(async _ => {
Assert.equal(cookies, "a=b", "Cookie even for different scheme!");
}
cookies = Services.cookies.getCookieStringForPrincipal(principal);
cookies = await CookieXPCShellUtils.getCookieStringFromDocument(uri.spec);
if (schemefulComparison) {
Assert.equal(cookies, "", "No cookie for different scheme!");
} else {
@ -191,3 +210,78 @@ add_task(async _ => {
Services.cookies.removeAll();
});
[
{
prefValue: true,
consoleMessage: `Cookie “a” has been treated as cross-site against “http://example.org/” because the scheme does not match.`,
},
{
prefValue: false,
consoleMessage: `Cookie “a” will be soon treated as cross-site cookie against “http://example.org/” because the scheme does not match.`,
},
].forEach(test => {
add_task(async () => {
do_get_profile();
maybeInitializeCookieXPCShellUtils();
// Allow all cookies if the pref service is available in this process.
if (!inChildProcess()) {
Services.prefs.setBoolPref(
"network.cookie.sameSite.schemeful",
test.prefValue
);
Services.prefs.setIntPref("network.cookie.cookieBehavior", 0);
Services.prefs.setBoolPref(
"network.cookieJarSettings.unblocked_for_testing",
true
);
}
let cs = Cc["@mozilla.org/cookieService;1"].getService(Ci.nsICookieService);
info("Let's set a cookie from HTTPS example.org");
let uri = NetUtil.newURI("https://example.org/");
let principal = Services.scriptSecurityManager.createContentPrincipal(
uri,
{}
);
let channel = NetUtil.newChannel({
uri,
loadingPrincipal: principal,
securityFlags: Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
contentPolicyType: Ci.nsIContentPolicy.TYPE_OTHER,
});
cs.setCookieStringFromHttp(uri, "a=b; sameSite=lax", channel);
// Create a console listener.
let consolePromise = new Promise(resolve => {
let listener = {
observe(message) {
// Ignore unexpected messages.
if (!(message instanceof Ci.nsIConsoleMessage)) {
return;
}
if (message.message.includes(test.consoleMessage)) {
Services.console.unregisterListener(listener);
resolve();
}
},
};
Services.console.registerListener(listener);
});
const contentPage = await CookieXPCShellUtils.loadContentPage(
"http://example.org/"
);
await contentPage.close();
await consolePromise;
Services.cookies.removeAll();
});
});

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

@ -63,5 +63,9 @@ CookieLaxForcedForBeta=Cookie “%1$S” does not have a proper “sameSite” a
CookieSameSiteValueInvalid=Invalid “sameSite“ value for cookie “%1$S”. The supported values are: “lax“, “strict“, “none“.
# LOCALIZATION NOTE (CookieOversize): %1$S is the cookie name. %2$S is the number of bytes. "B" means bytes.
CookieOversize=Cookie “%1$S” is invalid because its size is too big. Max size is %2$S B.
# LOCALIZATION NOTE (CookiePathOversiz): %1$S is the cookie name. %2$S is the number of bytes. "B" means bytes.
# LOCALIZATION NOTE (CookiePathOversize): %1$S is the cookie name. %2$S is the number of bytes. "B" means bytes.
CookiePathOversize=Cookie “%1$S” is invalid because its path size is too big. Max size is %2$S B.
# LOCALIZATION NOTE (CookieSchemefulRejectForBeta): %1$S is the cookie name. %2$S is the hostname.
CookieSchemefulRejectForBeta=Cookie “%1$S” will be soon treated as cross-site cookie against “%2$S” because the scheme does not match.
# LOCALIZATION NOTE (CookieSchemefulReject): %1$S is the cookie name. %2$S is the hostname.
CookieSchemefulReject=Cookie “%1$S” has been treated as cross-site against “%2$S” because the scheme does not match.