зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1638358 - Cookie Schemeful Same-Site - part 5 - schemeful comparison, r=mayhemer
Differential Revision: https://phabricator.services.mozilla.com/D75629
This commit is contained in:
Родитель
8170437e2e
Коммит
97f0db059a
|
@ -13,7 +13,13 @@ add_task(async function setup() {
|
|||
|
||||
// make sure userContext is enabled.
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["privacy.userContext.enabled", true]],
|
||||
set: [
|
||||
["privacy.userContext.enabled", true],
|
||||
// This test does a redirect from https to http and it checks the
|
||||
// cookies. This is incompatible with the cookie sameSite schemeful
|
||||
// feature and we need to disable it.
|
||||
["network.cookie.sameSite.schemeful", false],
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -855,6 +855,19 @@ NS_IMETHODIMP BasePrincipal::GetIsIpAddress(bool* aIsIpAddress) {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BasePrincipal::GetScheme(nsACString& aScheme) {
|
||||
aScheme.Truncate();
|
||||
|
||||
nsCOMPtr<nsIURI> prinURI;
|
||||
nsresult rv = GetURI(getter_AddRefs(prinURI));
|
||||
if (NS_FAILED(rv) || !prinURI) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return prinURI->GetScheme(aScheme);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BasePrincipal::SchemeIs(const char* aScheme, bool* aResult) {
|
||||
*aResult = false;
|
||||
|
|
|
@ -122,6 +122,7 @@ class BasePrincipal : public nsJSPrincipals {
|
|||
NS_IMETHOD GetIsContentPrincipal(bool* aResult) override;
|
||||
NS_IMETHOD GetIsExpandedPrincipal(bool* aResult) override;
|
||||
NS_IMETHOD GetIsSystemPrincipal(bool* aResult) override;
|
||||
NS_IMETHOD GetScheme(nsACString& aScheme) override;
|
||||
NS_IMETHOD SchemeIs(const char* aScheme, bool* aResult) override;
|
||||
NS_IMETHOD IsURIInPrefList(const char* aPref, bool* aResult) override;
|
||||
NS_IMETHOD IsL10nAllowed(nsIURI* aURI, bool* aResult) override;
|
||||
|
|
|
@ -287,7 +287,12 @@ interface nsIPrincipal : nsISerializable
|
|||
/* Returns the Spec of the Principals URI with
|
||||
* user/pass/ref/query stripped for privacy and spoof prevention
|
||||
*/
|
||||
readonly attribute ACString exposableSpec;
|
||||
readonly attribute ACString exposableSpec;
|
||||
|
||||
/**
|
||||
* Return the scheme of the principals URI
|
||||
*/
|
||||
readonly attribute ACString scheme;
|
||||
|
||||
/**
|
||||
* Checks if the Principal's URI Scheme matches with the parameter
|
||||
|
|
|
@ -7505,6 +7505,11 @@
|
|||
value: @IS_NIGHTLY_BUILD@
|
||||
mirror: always
|
||||
|
||||
- name: network.cookie.sameSite.schemeful
|
||||
type: bool
|
||||
value: @IS_NIGHTLY_BUILD@
|
||||
mirror: always
|
||||
|
||||
- name: network.cookie.thirdparty.sessionOnly
|
||||
type: bool
|
||||
value: false
|
||||
|
|
|
@ -456,5 +456,65 @@ 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;
|
||||
}
|
||||
|
||||
// This is an old cookie without a scheme yet. Let's consider it valid.
|
||||
if (aCookie->SchemeMap() == nsICookie::SCHEME_UNSET) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return !!(aCookie->SchemeMap() & aSchemeType);
|
||||
}
|
||||
|
||||
// static
|
||||
nsICookie::schemeType CookieCommons::URIToSchemeType(nsIURI* aURI) {
|
||||
MOZ_ASSERT(aURI);
|
||||
|
||||
nsAutoCString scheme;
|
||||
nsresult rv = aURI->GetScheme(scheme);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nsICookie::SCHEME_UNSET;
|
||||
}
|
||||
|
||||
return SchemeToSchemeType(scheme);
|
||||
}
|
||||
|
||||
// static
|
||||
nsICookie::schemeType CookieCommons::PrincipalToSchemeType(
|
||||
nsIPrincipal* aPrincipal) {
|
||||
MOZ_ASSERT(aPrincipal);
|
||||
|
||||
nsAutoCString scheme;
|
||||
nsresult rv = aPrincipal->GetScheme(scheme);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nsICookie::SCHEME_UNSET;
|
||||
}
|
||||
|
||||
return SchemeToSchemeType(scheme);
|
||||
}
|
||||
|
||||
// static
|
||||
nsICookie::schemeType CookieCommons::SchemeToSchemeType(
|
||||
const nsACString& aScheme) {
|
||||
if (aScheme.Equals("https")) {
|
||||
return nsICookie::SCHEME_HTTPS;
|
||||
}
|
||||
|
||||
if (aScheme.Equals("http")) {
|
||||
return nsICookie::SCHEME_HTTP;
|
||||
}
|
||||
|
||||
if (aScheme.Equals("file")) {
|
||||
return nsICookie::SCHEME_FILE;
|
||||
}
|
||||
|
||||
MOZ_CRASH("Unsupported scheme type");
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -108,6 +108,15 @@ class CookieCommons final {
|
|||
nsIChannel* aChannel);
|
||||
|
||||
static bool ShouldIncludeCrossSiteCookieForDocument(Cookie* aCookie);
|
||||
|
||||
static bool MaybeCompareScheme(Cookie* aCookie,
|
||||
nsICookie::schemeType aSchemeType);
|
||||
|
||||
static nsICookie::schemeType URIToSchemeType(nsIURI* aURI);
|
||||
|
||||
static nsICookie::schemeType PrincipalToSchemeType(nsIPrincipal* aPrincipal);
|
||||
|
||||
static nsICookie::schemeType SchemeToSchemeType(const nsACString& aScheme);
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
|
|
|
@ -284,6 +284,9 @@ CookieService::GetCookieStringFromDocument(Document* aDocument,
|
|||
|
||||
nsCOMPtr<nsIPrincipal> principal = aDocument->EffectiveStoragePrincipal();
|
||||
|
||||
nsICookie::schemeType schemeType =
|
||||
CookieCommons::PrincipalToSchemeType(principal);
|
||||
|
||||
CookieStorage* storage = PickStorage(principal->OriginAttributesRef());
|
||||
|
||||
nsAutoCString baseDomain;
|
||||
|
@ -352,6 +355,10 @@ CookieService::GetCookieStringFromDocument(Document* aDocument,
|
|||
continue;
|
||||
}
|
||||
|
||||
if (!CookieCommons::MaybeCompareScheme(cookie, schemeType)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// if the nsIURI path doesn't match the cookie path, don't send it back
|
||||
if (!CookieCommons::PathMatches(cookie, pathFromURI)) {
|
||||
continue;
|
||||
|
@ -849,6 +856,8 @@ void CookieService::GetCookiesForURI(
|
|||
baseDomainFromURI);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
||||
nsICookie::schemeType schemeType = CookieCommons::URIToSchemeType(aHostURI);
|
||||
|
||||
// check default prefs
|
||||
uint32_t rejectedReason = aRejectedReason;
|
||||
uint32_t priorCookieCount = storage->CountCookiesFromHost(
|
||||
|
@ -913,6 +922,11 @@ void CookieService::GetCookiesForURI(
|
|||
continue;
|
||||
}
|
||||
|
||||
// The scheme doesn't match.
|
||||
if (!CookieCommons::MaybeCompareScheme(cookie, schemeType)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (aHttpBound && aIsSameSiteForeign &&
|
||||
!ProcessSameSiteCookieForForeignRequest(
|
||||
aChannel, cookie, aIsSafeTopLevelNav, laxByDefault)) {
|
||||
|
@ -977,15 +991,7 @@ bool CookieService::CanSetCookie(
|
|||
// init expiryTime such that session cookies won't prematurely expire
|
||||
aCookieData.expiry() = INT64_MAX;
|
||||
|
||||
if (aHostURI->SchemeIs("https")) {
|
||||
aCookieData.schemeMap() = nsICookie::SCHEME_HTTPS;
|
||||
} else if (aHostURI->SchemeIs("http")) {
|
||||
aCookieData.schemeMap() = nsICookie::SCHEME_HTTP;
|
||||
} else if (aHostURI->SchemeIs("file")) {
|
||||
aCookieData.schemeMap() = nsICookie::SCHEME_FILE;
|
||||
} else {
|
||||
MOZ_CRASH("Unsupported scheme type");
|
||||
}
|
||||
aCookieData.schemeMap() = CookieCommons::URIToSchemeType(aHostURI);
|
||||
|
||||
// aCookieHeader is an in/out param to point to the next cookie, if
|
||||
// there is one. Save the present value for logging purposes
|
||||
|
|
|
@ -331,6 +331,9 @@ CookieServiceChild::GetCookieStringFromDocument(Document* aDocument,
|
|||
|
||||
nsCOMPtr<nsIPrincipal> principal = aDocument->EffectiveStoragePrincipal();
|
||||
|
||||
nsICookie::schemeType schemeType =
|
||||
CookieCommons::PrincipalToSchemeType(principal);
|
||||
|
||||
nsAutoCString baseDomain;
|
||||
nsresult rv = CookieCommons::GetBaseDomain(principal, baseDomain);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
|
@ -388,6 +391,10 @@ CookieServiceChild::GetCookieStringFromDocument(Document* aDocument,
|
|||
continue;
|
||||
}
|
||||
|
||||
if (!CookieCommons::MaybeCompareScheme(cookie, schemeType)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// if the nsIURI path doesn't match the cookie path, don't send it back
|
||||
if (!CookieCommons::PathMatches(cookie, pathFromURI)) {
|
||||
continue;
|
||||
|
|
|
@ -1,6 +1,17 @@
|
|||
const { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
var { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
Services,
|
||||
"cookiemgr",
|
||||
"@mozilla.org/cookiemanager;1",
|
||||
"nsICookieManager"
|
||||
);
|
||||
|
||||
function inChildProcess() {
|
||||
return Services.appinfo.processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
|
||||
}
|
||||
|
@ -61,4 +72,122 @@ add_task(async _ => {
|
|||
Ci.nsICookie.SCHEME_HTTP | Ci.nsICookie.SCHEME_HTTPS,
|
||||
"HTTP + HTTPS Schemes"
|
||||
);
|
||||
|
||||
Services.cookies.removeAll();
|
||||
});
|
||||
|
||||
[true, false].forEach(schemefulComparison => {
|
||||
add_task(async () => {
|
||||
do_get_profile();
|
||||
|
||||
// Allow all cookies if the pref service is available in this process.
|
||||
if (!inChildProcess()) {
|
||||
Services.prefs.setBoolPref(
|
||||
"network.cookie.sameSite.schemeful",
|
||||
schemefulComparison
|
||||
);
|
||||
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 HTTP example.org");
|
||||
|
||||
let uri = NetUtil.newURI("http://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);
|
||||
|
||||
let cookies = Services.cookies.getCookieStringFromHttp(uri, channel);
|
||||
Assert.equal(cookies, "a=b", "Cookies match");
|
||||
|
||||
uri = NetUtil.newURI("https://example.org/");
|
||||
principal = Services.scriptSecurityManager.createContentPrincipal(uri, {});
|
||||
channel = NetUtil.newChannel({
|
||||
uri,
|
||||
loadingPrincipal: principal,
|
||||
securityFlags: Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
|
||||
contentPolicyType: Ci.nsIContentPolicy.TYPE_OTHER,
|
||||
});
|
||||
|
||||
cookies = Services.cookies.getCookieStringFromHttp(uri, channel);
|
||||
if (schemefulComparison) {
|
||||
Assert.equal(cookies, "", "No cookie for different scheme!");
|
||||
} else {
|
||||
Assert.equal(cookies, "a=b", "Cookie even for different scheme!");
|
||||
}
|
||||
|
||||
cookies = Services.cookies.getCookieStringForPrincipal(principal);
|
||||
if (schemefulComparison) {
|
||||
Assert.equal(cookies, "", "No cookie for different scheme!");
|
||||
} else {
|
||||
Assert.equal(cookies, "a=b", "Cookie even for different scheme!");
|
||||
}
|
||||
|
||||
Services.cookies.removeAll();
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async _ => {
|
||||
do_get_profile();
|
||||
|
||||
// Allow all cookies if the pref service is available in this process.
|
||||
if (!inChildProcess()) {
|
||||
Services.prefs.setIntPref("network.cookie.cookieBehavior", 0);
|
||||
Services.prefs.setBoolPref(
|
||||
"network.cookieJarSettings.unblocked_for_testing",
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
info("Let's set a cookie without scheme");
|
||||
Services.cookiemgr.add(
|
||||
"example.org",
|
||||
"/",
|
||||
"a",
|
||||
"b",
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
Math.floor(Date.now() / 1000 + 1000),
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_LAX,
|
||||
Ci.nsICookie.SCHEME_UNSET
|
||||
);
|
||||
|
||||
let cookies = Services.cookies.getCookiesFromHost("example.org", {});
|
||||
Assert.equal(cookies.length, 1, "We expect 1 cookie only");
|
||||
Assert.equal(cookies[0].schemeMap, Ci.nsICookie.SCHEME_UNSET, "Unset scheme");
|
||||
|
||||
["https", "http"].forEach(scheme => {
|
||||
let uri = NetUtil.newURI(scheme + "://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,
|
||||
});
|
||||
|
||||
cookies = Services.cookies.getCookieStringFromHttp(uri, channel);
|
||||
Assert.equal(cookies, "a=b", "Cookie for unset scheme");
|
||||
});
|
||||
|
||||
Services.cookies.removeAll();
|
||||
});
|
||||
|
|
|
@ -199,6 +199,7 @@ void InitPrefs(nsIPrefBranch* aPrefBranch) {
|
|||
Preferences::SetBool("network.cookie.sameSite.laxByDefault", false);
|
||||
Preferences::SetBool("network.cookieJarSettings.unblocked_for_testing", true);
|
||||
Preferences::SetBool("dom.securecontext.whitelist_onions", false);
|
||||
Preferences::SetBool("network.cookie.sameSite.schemeful", false);
|
||||
}
|
||||
|
||||
TEST(TestCookie, TestCookieMain)
|
||||
|
@ -725,6 +726,7 @@ TEST(TestCookie, TestCookieMain)
|
|||
GetACookieNoHttp(cookieService, "https://www.security.test/", cookie);
|
||||
EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL,
|
||||
"test_modify_cookie=non-security-cookie"));
|
||||
|
||||
// Test the non-security cookie can set when domain or path not same to secure
|
||||
// cookie of same name.
|
||||
SetACookie(cookieService, "https://www.security.test/", "test=security3");
|
||||
|
@ -735,6 +737,11 @@ TEST(TestCookie, TestCookieMain)
|
|||
GetACookieNoHttp(cookieService, "http://www.security.test/", cookie);
|
||||
EXPECT_TRUE(CheckResult(cookie.get(), MUST_CONTAIN, "test=non-security2"));
|
||||
|
||||
Preferences::SetBool("network.cookie.sameSite.schemeful", true);
|
||||
GetACookieNoHttp(cookieService, "http://www.security.test/", cookie);
|
||||
EXPECT_FALSE(CheckResult(cookie.get(), MUST_CONTAIN, "test=security3"));
|
||||
Preferences::SetBool("network.cookie.sameSite.schemeful", false);
|
||||
|
||||
// *** nsICookieManager interface tests
|
||||
nsCOMPtr<nsICookieManager> cookieMgr =
|
||||
do_GetService(NS_COOKIEMANAGER_CONTRACTID, &rv0);
|
||||
|
|
|
@ -36,7 +36,12 @@ function setupTest(uri, domain, cookies, loads, headers) {
|
|||
|
||||
var prefSet = new Promise(resolve => {
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{ set: [["network.cookie.cookieBehavior", 1]] },
|
||||
{
|
||||
set: [
|
||||
["network.cookie.cookieBehavior", 1],
|
||||
["network.cookie.sameSite.schemeful", false],
|
||||
],
|
||||
},
|
||||
resolve
|
||||
);
|
||||
});
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
prefs: [network.cookie.sameSite.schemeful:false]
|
|
@ -0,0 +1 @@
|
|||
prefs: [network.cookie.sameSite.schemeful:false]
|
Загрузка…
Ссылка в новой задаче