Bug 1260931 - Part 1: add firstPartyDomain. r=smaug

Add an origin attribute called 'firstPartyDomain'.
This value will be extracted from the URL bar.

And the purpose of this attribute is used to isolate the data-jars.
Please see the tor documentation.
https://www.torproject.org/projects/torbrowser/design/#identifier-linkability

The idea is like a superset of 'reject third party cookies', but not
only apply for cookies, it also applies to all data-jars like localStorage,
indexedDB and so on.

So basically an iframe will have its own data-jar, and this data-jar is
isolated by the URL from URL bar, for instance, an iframe
https://facebook.com inside https://cnn.com won't share data-jar with
the iframe (https://facebook.com) in https://bbc.com
This commit is contained in:
Yoshi Huang 2016-08-09 16:34:53 +08:00
parent b5da131303
commit 85a594681d
4 changed files with 69 additions and 7 deletions

View File

@ -47,6 +47,7 @@ PrincipalOriginAttributes::InheritFromDocShellToDoc(const DocShellOriginAttribut
mSignedPkg = aAttrs.mSignedPkg;
mPrivateBrowsingId = aAttrs.mPrivateBrowsingId;
mFirstPartyDomain = aAttrs.mFirstPartyDomain;
}
void
@ -60,6 +61,7 @@ PrincipalOriginAttributes::InheritFromNecko(const NeckoOriginAttributes& aAttrs)
mSignedPkg = aAttrs.mSignedPkg;
mPrivateBrowsingId = aAttrs.mPrivateBrowsingId;
mFirstPartyDomain = aAttrs.mFirstPartyDomain;
}
void
@ -77,6 +79,7 @@ DocShellOriginAttributes::InheritFromDocToChildDocShell(const PrincipalOriginAtt
mSignedPkg = aAttrs.mSignedPkg;
mPrivateBrowsingId = aAttrs.mPrivateBrowsingId;
mFirstPartyDomain = aAttrs.mFirstPartyDomain;
}
void
@ -93,6 +96,7 @@ NeckoOriginAttributes::InheritFromDocToNecko(const PrincipalOriginAttributes& aA
// mSignedPkg accordingly by mSignedPkgInBrowser
mPrivateBrowsingId = aAttrs.mPrivateBrowsingId;
mFirstPartyDomain = aAttrs.mFirstPartyDomain;
}
void
@ -109,6 +113,7 @@ NeckoOriginAttributes::InheritFromDocShellToNecko(const DocShellOriginAttributes
// mSignedPkg accordingly by mSignedPkgInBrowser
mPrivateBrowsingId = aAttrs.mPrivateBrowsingId;
mFirstPartyDomain = aAttrs.mFirstPartyDomain;
}
void
@ -161,6 +166,11 @@ OriginAttributes::CreateSuffix(nsACString& aStr) const
params->Set(NS_LITERAL_STRING("privateBrowsingId"), value);
}
if (!mFirstPartyDomain.IsEmpty()) {
MOZ_RELEASE_ASSERT(mFirstPartyDomain.FindCharInSet(dom::quota::QuotaManager::kReplaceChars) == kNotFound);
params->Set(NS_LITERAL_STRING("firstPartyDomain"), mFirstPartyDomain);
}
aStr.Truncate();
params->Serialize(value);
@ -247,6 +257,12 @@ public:
return true;
}
if (aName.EqualsLiteral("firstPartyDomain")) {
MOZ_RELEASE_ASSERT(mOriginAttributes->mFirstPartyDomain.IsEmpty());
mOriginAttributes->mFirstPartyDomain.Assign(aValue);
return true;
}
// No other attributes are supported.
return false;
}
@ -307,6 +323,7 @@ OriginAttributes::SetFromGenericAttributes(const GenericOriginAttributes& aAttrs
mUserContextId = aAttrs.mUserContextId;
mSignedPkg = aAttrs.mSignedPkg;
mPrivateBrowsingId = aAttrs.mPrivateBrowsingId;
mFirstPartyDomain = aAttrs.mFirstPartyDomain;
}
BasePrincipal::BasePrincipal()

View File

@ -37,7 +37,8 @@ public:
mAddonId == aOther.mAddonId &&
mUserContextId == aOther.mUserContextId &&
mSignedPkg == aOther.mSignedPkg &&
mPrivateBrowsingId == aOther.mPrivateBrowsingId;
mPrivateBrowsingId == aOther.mPrivateBrowsingId &&
mFirstPartyDomain == aOther.mFirstPartyDomain;
}
bool operator!=(const OriginAttributes& aOther) const
{
@ -189,6 +190,10 @@ public:
return false;
}
if (mFirstPartyDomain.WasPassed() && mFirstPartyDomain.Value() != aAttrs.mFirstPartyDomain) {
return false;
}
return true;
}
@ -225,6 +230,11 @@ public:
return false;
}
if (mFirstPartyDomain.WasPassed() && aOther.mFirstPartyDomain.WasPassed() &&
mFirstPartyDomain.Value() != aOther.mFirstPartyDomain.Value()) {
return false;
}
return true;
}
};

View File

@ -42,7 +42,9 @@ function printAttrs(name, attrs) {
"\tuserContextId: " + attrs.userContextId + ",\n" +
"\tinIsolatedMozBrowser: " + attrs.inIsolatedMozBrowser + ",\n" +
"\taddonId: '" + attrs.addonId + "',\n" +
"\tsignedPkg: '" + attrs.signedPkg + "'\n}");
"\tsignedPkg: '" + attrs.signedPkg + "',\n" +
"\tprivateBrowsingId: '" + attrs.privateBrowsingId + "',\n" +
"\tfirstPartyDomain: '" + attrs.firstPartyDomain + "'\n}");
}
@ -55,6 +57,8 @@ function checkValues(attrs, values) {
do_check_eq(attrs.inIsolatedMozBrowser, values.inIsolatedMozBrowser || false);
do_check_eq(attrs.addonId, values.addonId || '');
do_check_eq(attrs.signedPkg, values.signedPkg || '');
do_check_eq(attrs.privateBrowsingId, values.privateBrowsingId || '');
do_check_eq(attrs.firstPartyDomain, values.firstPartyDomain || '');
}
function run_test() {
@ -122,6 +126,11 @@ function run_test() {
checkOriginAttributes(exampleOrg_addon, { addonId: "dummy" }, '^addonId=dummy');
do_check_eq(exampleOrg_addon.origin, 'http://example.org^addonId=dummy');
// First party Uri
var exampleOrg_firstPartyDomain = ssm.createCodebasePrincipal(makeURI('http://example.org'), {firstPartyDomain: 'example.org'});
checkOriginAttributes(exampleOrg_firstPartyDomain, { firstPartyDomain: "example.org" }, '^firstPartyDomain=example.org');
do_check_eq(exampleOrg_firstPartyDomain.origin, 'http://example.org^firstPartyDomain=example.org');
// Make sure we don't crash when serializing principals with UNKNOWN_APP_ID.
try {
let binaryStream = Cc["@mozilla.org/binaryoutputstream;1"].
@ -177,6 +186,7 @@ function run_test() {
checkCrossOrigin(exampleOrg_appBrowser, nullPrin_appBrowser);
checkCrossOrigin(exampleOrg_appBrowser, exampleCom_appBrowser);
checkCrossOrigin(exampleOrg_addon, exampleOrg);
checkCrossOrigin(exampleOrg_firstPartyDomain, exampleOrg);
checkCrossOrigin(exampleOrg_userContext, exampleOrg);
checkCrossOrigin(exampleOrg_userContextAddon, exampleOrg);
checkCrossOrigin(exampleOrg_userContext, exampleOrg_userContextAddon);
@ -203,7 +213,7 @@ function run_test() {
// check that we can create an empty origin attributes dict with default
// members and values.
emptyAttrs = ChromeUtils.fillNonDefaultOriginAttributes({});
var emptyAttrs = ChromeUtils.fillNonDefaultOriginAttributes({});
checkValues(emptyAttrs);
var uri = "http://example.org";
@ -213,19 +223,20 @@ function run_test() {
[ "^userContextId=3", {userContextId: 3} ],
[ "^addonId=fooBar", {addonId: "fooBar"} ],
[ "^inBrowser=1", {inIsolatedMozBrowser: true} ],
[ "^firstPartyDomain=example.org", {firstPartyDomain: "example.org"} ],
[ "^signedPkg=bazQux", {signedPkg: "bazQux"} ],
[ "^appId=3&inBrowser=1&userContextId=6",
{appId: 3, userContextId: 6, inIsolatedMozBrowser: true} ] ];
// check that we can create an origin attributes from an origin properly
tests.forEach(function(t) {
tests.forEach(t => {
let attrs = ChromeUtils.createOriginAttributesFromOrigin(uri + t[0]);
checkValues(attrs, t[1]);
do_check_eq(ChromeUtils.originAttributesToSuffix(attrs), t[0]);
});
// check that we can create an origin attributes from a dict properly
tests.forEach(function(t) {
tests.forEach(t => {
let attrs = ChromeUtils.fillNonDefaultOriginAttributes(t[1]);
checkValues(attrs, t[1]);
do_check_eq(ChromeUtils.originAttributesToSuffix(attrs), t[0]);
@ -244,7 +255,7 @@ function run_test() {
[ "^appId=5", {appId: 5}, {appId: 3, userContextId: 7}, {appId: 3, userContextId: 7}, "^appId=3&userContextId=7" ] ];
// check that we can set origin attributes values properly
set_tests.forEach(function(t) {
set_tests.forEach(t => {
let orig = ChromeUtils.createOriginAttributesFromOrigin(uri + t[0]);
checkValues(orig, t[1]);
let mod = orig;
@ -267,7 +278,7 @@ function run_test() {
[ "^appId=5&userContextId=3", {appId: 5, userContextId: 3}, {appId: 5}, "^appId=5" ] ];
// check that we can set the userContextId to default properly
dflt_tests.forEach(function(t) {
dflt_tests.forEach(t => {
let orig = ChromeUtils.createOriginAttributesFromOrigin(uri + t[0]);
checkValues(orig, t[1]);
let mod = orig;
@ -275,4 +286,26 @@ function run_test() {
checkValues(mod, t[2]);
do_check_eq(ChromeUtils.originAttributesToSuffix(mod), t[3]);
});
// each row in the dflt2_tests array has these values:
// [0] - the suffix used to create an origin attribute from
// [1] - the expected result of creating an origin attributes from [0]
// [2] - the expected result after setting firstPartyUri to the default
// [3] - the expected result of creating a suffix from [2]
var dflt2_tests = [
[ "", {}, {}, "" ],
[ "^firstPartyDomain=foo.com", {firstPartyDomain: "foo.com"}, {}, "" ],
[ "^appId=5", {appId: 5}, {appId: 5}, "^appId=5" ],
[ "^appId=5&firstPartyDomain=foo.com", {appId: 5, firstPartyDomain: "foo.com"}, {appId: 5}, "^appId=5" ] ];
// check that we can set the userContextId to default properly
dflt2_tests.forEach(t => {
let orig = ChromeUtils.createOriginAttributesFromOrigin(uri + t[0]);
checkValues(orig, t[1]);
let mod = orig;
mod['firstPartyDomain'] = "";
checkValues(mod, t[2]);
do_check_eq(ChromeUtils.originAttributesToSuffix(mod), t[3]);
});
}

View File

@ -81,6 +81,7 @@ dictionary OriginAttributesDictionary {
DOMString addonId = "";
DOMString signedPkg = "";
unsigned long privateBrowsingId = 0;
DOMString firstPartyDomain = "";
};
dictionary OriginAttributesPatternDictionary {
unsigned long appId;
@ -89,4 +90,5 @@ dictionary OriginAttributesPatternDictionary {
DOMString addonId;
DOMString signedPkg;
unsigned long privateBrowsingId;
DOMString firstPartyDomain;
};