Bug 1596741 - Emit warning to console when rejecting to set cookie, r=baku,flod

Differential Revision: https://phabricator.services.mozilla.com/D83649
This commit is contained in:
Honza Bambas 2020-07-18 05:23:54 +00:00
parent 53afe3b2f2
commit d4dd583612
6 changed files with 159 additions and 39 deletions

View File

@ -57,6 +57,7 @@ static StaticRefPtr<CookieService> gCookieService;
constexpr auto CONSOLE_SAMESITE_CATEGORY = "cookieSameSite"_ns;
constexpr auto CONSOLE_OVERSIZE_CATEGORY = "cookiesOversize"_ns;
constexpr auto CONSOLE_REJECTION_CATEGORY = "cookiesRejection"_ns;
constexpr auto SAMESITE_MDN_URL =
"https://developer.mozilla.org/docs/Web/HTTP/Headers/Set-Cookie/"
u"SameSite"_ns;
@ -485,9 +486,13 @@ CookieService::SetCookieStringFromDocument(Document* aDocument,
return NS_OK;
}
nsCOMPtr<nsIConsoleReportCollector> crc =
do_QueryInterface(aDocument->GetChannel());
// add the cookie to the list. AddCookie() takes care of logging.
PickStorage(attrs)->AddCookie(baseDomain, attrs, cookie, currentTimeInUsec,
documentURI, aCookieString, false);
PickStorage(attrs)->AddCookie(crc, baseDomain, attrs, cookie,
currentTimeInUsec, documentURI, aCookieString,
false);
return NS_OK;
}
@ -548,8 +553,10 @@ CookieService::SetCookieStringFromHttp(nsIURI* aHostURI,
uint32_t priorCookieCount = storage->CountCookiesFromHost(
baseDomainFromURI, attrs.mPrivateBrowsingId);
nsCOMPtr<nsIConsoleReportCollector> crc = do_QueryInterface(aChannel);
CookieStatus cookieStatus = CheckPrefs(
cookieJarSettings, aHostURI,
crc, cookieJarSettings, aHostURI,
result.contains(ThirdPartyAnalysis::IsForeign),
result.contains(ThirdPartyAnalysis::IsThirdPartyTrackingResource),
result.contains(ThirdPartyAnalysis::IsThirdPartySocialTrackingResource),
@ -592,8 +599,6 @@ CookieService::SetCookieStringFromHttp(nsIURI* aHostURI,
nsCString cookieHeader(aCookieHeader);
nsCOMPtr<nsIConsoleReportCollector> crc = do_QueryInterface(aChannel);
bool moreCookieToRead = true;
// process each cookie in the header
@ -617,6 +622,12 @@ CookieService::SetCookieStringFromHttp(nsIURI* aHostURI,
aHostURI, aChannel,
nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION,
OPERATION_WRITE);
CookieLogging::LogMessageToConsole(
crc, aHostURI, nsIScriptError::warningFlag,
CONSOLE_REJECTION_CATEGORY, "CookieRejectedByPermissionManager"_ns,
AutoTArray<nsString, 1>{
NS_ConvertUTF8toUTF16(cookieData.name()),
});
continue;
}
@ -630,8 +641,8 @@ CookieService::SetCookieStringFromHttp(nsIURI* aHostURI,
Cookie::GenerateUniqueCreationTime(currentTimeInUsec));
// add the cookie to the list. AddCookie() takes care of logging.
storage->AddCookie(baseDomain, attrs, cookie, currentTimeInUsec, aHostURI,
aCookieHeader, true);
storage->AddCookie(crc, baseDomain, attrs, cookie, currentTimeInUsec,
aHostURI, aCookieHeader, true);
}
return NS_OK;
@ -758,8 +769,8 @@ CookieService::AddNative(const nsACString& aHost, const nsACString& aPath,
MOZ_ASSERT(cookie);
CookieStorage* storage = PickStorage(*aOriginAttributes);
storage->AddCookie(baseDomain, *aOriginAttributes, cookie, currentTimeInUsec,
nullptr, VoidCString(), true);
storage->AddCookie(nullptr, baseDomain, *aOriginAttributes, cookie,
currentTimeInUsec, nullptr, VoidCString(), true);
return NS_OK;
}
@ -879,10 +890,12 @@ void CookieService::GetCookiesForURI(
uint32_t priorCookieCount = storage->CountCookiesFromHost(
baseDomainFromURI, aOriginAttrs.mPrivateBrowsingId);
nsCOMPtr<nsIConsoleReportCollector> crc = do_QueryInterface(aChannel);
CookieStatus cookieStatus = CheckPrefs(
cookieJarSettings, aHostURI, aIsForeign, aIsThirdPartyTrackingResource,
aIsThirdPartySocialTrackingResource, aStorageAccessPermissionGranted,
VoidCString(), priorCookieCount, aOriginAttrs, &rejectedReason);
crc, cookieJarSettings, aHostURI, aIsForeign,
aIsThirdPartyTrackingResource, aIsThirdPartySocialTrackingResource,
aStorageAccessPermissionGranted, VoidCString(), priorCookieCount,
aOriginAttrs, &rejectedReason);
MOZ_ASSERT_IF(rejectedReason, cookieStatus == STATUS_REJECTED);
@ -926,8 +939,6 @@ 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.
@ -1070,6 +1081,12 @@ bool CookieService::CanSetCookie(
if (!CookieCommons::CheckName(aCookieData)) {
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, savedCookieHeader,
"invalid name character");
CookieLogging::LogMessageToConsole(
aCRC, aHostURI, nsIScriptError::warningFlag, CONSOLE_REJECTION_CATEGORY,
"CookieRejectedInvalidCharName"_ns,
AutoTArray<nsString, 1>{
NS_ConvertUTF8toUTF16(aCookieData.name()),
});
return newCookie;
}
@ -1077,6 +1094,12 @@ bool CookieService::CanSetCookie(
if (!CheckDomain(aCookieData, aHostURI, aBaseDomain, aRequireHostMatch)) {
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, savedCookieHeader,
"failed the domain tests");
CookieLogging::LogMessageToConsole(
aCRC, aHostURI, nsIScriptError::warningFlag, CONSOLE_REJECTION_CATEGORY,
"CookieRejectedInvalidDomain"_ns,
AutoTArray<nsString, 1>{
NS_ConvertUTF8toUTF16(aCookieData.name()),
});
return newCookie;
}
@ -1090,12 +1113,24 @@ bool CookieService::CanSetCookie(
if (!CheckPrefixes(aCookieData, potentiallyTurstworthy)) {
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, savedCookieHeader,
"failed the prefix tests");
CookieLogging::LogMessageToConsole(
aCRC, aHostURI, nsIScriptError::warningFlag, CONSOLE_REJECTION_CATEGORY,
"CookieRejectedInvalidPrefix"_ns,
AutoTArray<nsString, 1>{
NS_ConvertUTF8toUTF16(aCookieData.name()),
});
return newCookie;
}
if (aFromHttp && !CookieCommons::CheckHttpValue(aCookieData)) {
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, savedCookieHeader,
"invalid value character");
CookieLogging::LogMessageToConsole(
aCRC, aHostURI, nsIScriptError::warningFlag, CONSOLE_REJECTION_CATEGORY,
"CookieRejectedInvalidCharValue"_ns,
AutoTArray<nsString, 1>{
NS_ConvertUTF8toUTF16(aCookieData.name()),
});
return newCookie;
}
@ -1103,6 +1138,12 @@ bool CookieService::CanSetCookie(
if (!aFromHttp && aCookieData.isHttpOnly()) {
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, savedCookieHeader,
"cookie is httponly; coming from script");
CookieLogging::LogMessageToConsole(
aCRC, aHostURI, nsIScriptError::warningFlag, CONSOLE_REJECTION_CATEGORY,
"CookieRejectedHttpOnlyButFromScript"_ns,
AutoTArray<nsString, 1>{
NS_ConvertUTF8toUTF16(aCookieData.name()),
});
return newCookie;
}
@ -1112,6 +1153,12 @@ bool CookieService::CanSetCookie(
if (aCookieData.isSecure() && !potentiallyTurstworthy) {
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader,
"non-https cookie can't set secure flag");
CookieLogging::LogMessageToConsole(
aCRC, aHostURI, nsIScriptError::warningFlag, CONSOLE_REJECTION_CATEGORY,
"CookieRejectedSecureButNonHttps"_ns,
AutoTArray<nsString, 1>{
NS_ConvertUTF8toUTF16(aCookieData.name()),
});
return newCookie;
}
@ -1478,15 +1525,13 @@ static inline bool IsSubdomainOf(const nsACString& a, const nsACString& b) {
return false;
}
CookieStatus CookieService::CheckPrefs(nsICookieJarSettings* aCookieJarSettings,
nsIURI* aHostURI, bool aIsForeign,
bool aIsThirdPartyTrackingResource,
bool aIsThirdPartySocialTrackingResource,
bool aStorageAccessPermissionGranted,
const nsACString& aCookieHeader,
const int aNumOfCookies,
const OriginAttributes& aOriginAttrs,
uint32_t* aRejectedReason) {
CookieStatus CookieService::CheckPrefs(
nsIConsoleReportCollector* aCRC, nsICookieJarSettings* aCookieJarSettings,
nsIURI* aHostURI, bool aIsForeign, bool aIsThirdPartyTrackingResource,
bool aIsThirdPartySocialTrackingResource,
bool aStorageAccessPermissionGranted, const nsACString& aCookieHeader,
const int aNumOfCookies, const OriginAttributes& aOriginAttrs,
uint32_t* aRejectedReason) {
nsresult rv;
MOZ_ASSERT(aRejectedReason);
@ -1522,6 +1567,13 @@ CookieStatus CookieService::CheckPrefs(nsICookieJarSettings* aCookieJarSettings,
COOKIE_LOGFAILURE(aCookieHeader.IsVoid() ? GET_COOKIE : SET_COOKIE,
aHostURI, aCookieHeader,
"cookies are blocked for this site");
CookieLogging::LogMessageToConsole(
aCRC, aHostURI, nsIScriptError::warningFlag,
CONSOLE_REJECTION_CATEGORY, "CookieRejectedByPermissionManager"_ns,
AutoTArray<nsString, 1>{
NS_ConvertUTF8toUTF16(aCookieHeader),
});
*aRejectedReason =
nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION;
return STATUS_REJECTED;
@ -1587,6 +1639,12 @@ CookieStatus CookieService::CheckPrefs(nsICookieJarSettings* aCookieJarSettings,
!aStorageAccessPermissionGranted) {
COOKIE_LOGFAILURE(aCookieHeader.IsVoid() ? GET_COOKIE : SET_COOKIE,
aHostURI, aCookieHeader, "context is third party");
CookieLogging::LogMessageToConsole(
aCRC, aHostURI, nsIScriptError::warningFlag,
CONSOLE_REJECTION_CATEGORY, "CookieRejectedThirdParty"_ns,
AutoTArray<nsString, 1>{
NS_ConvertUTF8toUTF16(aCookieHeader),
});
*aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN;
return STATUS_REJECTED;
}
@ -1595,6 +1653,12 @@ CookieStatus CookieService::CheckPrefs(nsICookieJarSettings* aCookieJarSettings,
!aStorageAccessPermissionGranted && aNumOfCookies == 0) {
COOKIE_LOGFAILURE(aCookieHeader.IsVoid() ? GET_COOKIE : SET_COOKIE,
aHostURI, aCookieHeader, "context is third party");
CookieLogging::LogMessageToConsole(
aCRC, aHostURI, nsIScriptError::warningFlag,
CONSOLE_REJECTION_CATEGORY, "CookieRejectedThirdParty"_ns,
AutoTArray<nsString, 1>{
NS_ConvertUTF8toUTF16(aCookieHeader),
});
*aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN;
return STATUS_REJECTED;
}
@ -2281,8 +2345,8 @@ bool CookieService::SetCookiesFromIPC(const nsACString& aBaseDomain,
cookie->SetCreationTime(
Cookie::GenerateUniqueCreationTime(currentTimeInUsec));
storage->AddCookie(aBaseDomain, aAttrs, cookie, currentTimeInUsec, aHostURI,
EmptyCString(), aFromHttp);
storage->AddCookie(nullptr, aBaseDomain, aAttrs, cookie, currentTimeInUsec,
aHostURI, EmptyCString(), aFromHttp);
}
return true;

View File

@ -71,15 +71,13 @@ class CookieService final : public nsICookieService,
CookieStatus aStatus, nsCString& aCookieHeader,
bool aFromHttp, bool aIsForeignAndNotAddon,
nsIConsoleReportCollector* aCRC, bool& aSetCookie);
static CookieStatus CheckPrefs(nsICookieJarSettings* aCookieJarSettings,
nsIURI* aHostURI, bool aIsForeign,
bool aIsThirdPartyTrackingResource,
bool aIsThirdPartySocialTrackingResource,
bool aStorageAccessPermissionGranted,
const nsACString& aCookieHeader,
const int aNumOfCookies,
const OriginAttributes& aOriginAttrs,
uint32_t* aRejectedReason);
static CookieStatus CheckPrefs(
nsIConsoleReportCollector* aCRC, nsICookieJarSettings* aCookieJarSettings,
nsIURI* aHostURI, bool aIsForeign, bool aIsThirdPartyTrackingResource,
bool aIsThirdPartySocialTrackingResource,
bool aStorageAccessPermissionGranted, const nsACString& aCookieHeader,
const int aNumOfCookies, const OriginAttributes& aOriginAttrs,
uint32_t* aRejectedReason);
void GetCookiesForURI(nsIURI* aHostURI, nsIChannel* aChannel, bool aIsForeign,
bool aIsThirdPartyTrackingResource,

View File

@ -542,8 +542,10 @@ CookieServiceChild::SetCookieStringFromHttp(nsIURI* aHostURI,
nsCOMPtr<nsICookieJarSettings> cookieJarSettings =
CookieCommons::GetCookieJarSettings(aChannel);
nsCOMPtr<nsIConsoleReportCollector> crc = do_QueryInterface(aChannel);
CookieStatus cookieStatus = CookieService::CheckPrefs(
cookieJarSettings, aHostURI,
crc, cookieJarSettings, aHostURI,
result.contains(ThirdPartyAnalysis::IsForeign),
result.contains(ThirdPartyAnalysis::IsThirdPartyTrackingResource),
result.contains(ThirdPartyAnalysis::IsThirdPartySocialTrackingResource),
@ -574,8 +576,6 @@ CookieServiceChild::SetCookieStringFromHttp(nsIURI* aHostURI,
&isForeignAndNotAddon);
}
nsCOMPtr<nsIConsoleReportCollector> crc = do_QueryInterface(aChannel);
bool moreCookies;
do {
CookieStruct cookieData;
@ -591,6 +591,12 @@ CookieServiceChild::SetCookieStringFromHttp(nsIURI* aHostURI,
if (!CookieCommons::CheckCookiePermission(aChannel, cookieData)) {
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieString,
"cookie rejected by permission manager");
CookieLogging::LogMessageToConsole(
crc, aHostURI, nsIScriptError::warningFlag,
CONSOLE_REJECTION_CATEGORY, "CookieRejectedByPermissionManager"_ns,
AutoTArray<nsString, 1>{
NS_ConvertUTF8toUTF16(cookieData.name()),
});
CookieCommons::NotifyRejected(
aHostURI, aChannel,
nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION,

View File

@ -395,7 +395,8 @@ void CookieStorage::NotifyChanged(nsISupports* aSubject, const char16_t* aData,
// replaces an existing cookie; or adds the cookie to the hashtable, and
// deletes a cookie (if maximum number of cookies has been reached). also
// performs list maintenance by removing expired cookies.
void CookieStorage::AddCookie(const nsACString& aBaseDomain,
void CookieStorage::AddCookie(nsIConsoleReportCollector* aCRC,
const nsACString& aBaseDomain,
const OriginAttributes& aOriginAttributes,
Cookie* aCookie, int64_t aCurrentTimeInUsec,
nsIURI* aHostURI, const nsACString& aCookieHeader,
@ -430,6 +431,12 @@ void CookieStorage::AddCookie(const nsACString& aBaseDomain,
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader,
"cookie can't save because older cookie is secure "
"cookie but newer cookie is non-secure cookie");
CookieLogging::LogMessageToConsole(
aCRC, aHostURI, nsIScriptError::warningFlag, CONSOLE_REJECTION_CATEGORY,
"CookieRejectedNonsecureOverSecure"_ns,
AutoTArray<nsString, 1>{
NS_ConvertUTF8toUTF16(aCookie->Name()),
});
return;
}
@ -448,6 +455,12 @@ void CookieStorage::AddCookie(const nsACString& aBaseDomain,
// The new cookie has expired and the old one is stale. Nothing to do.
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader,
"cookie has already expired");
CookieLogging::LogMessageToConsole(
aCRC, aHostURI, nsIScriptError::warningFlag,
CONSOLE_REJECTION_CATEGORY, "CookieRejectedExpired"_ns,
AutoTArray<nsString, 1>{
NS_ConvertUTF8toUTF16(aCookie->Name()),
});
return;
}
@ -469,6 +482,13 @@ void CookieStorage::AddCookie(const nsACString& aBaseDomain,
COOKIE_LOGFAILURE(
SET_COOKIE, aHostURI, aCookieHeader,
"previously stored cookie is httponly; coming from script");
CookieLogging::LogMessageToConsole(
aCRC, aHostURI, nsIScriptError::warningFlag,
CONSOLE_REJECTION_CATEGORY,
"CookieRejectedHttpOnlyButFromScript"_ns,
AutoTArray<nsString, 1>{
NS_ConvertUTF8toUTF16(aCookie->Name()),
});
return;
}
@ -504,6 +524,12 @@ void CookieStorage::AddCookie(const nsACString& aBaseDomain,
if (aCookie->Expiry() <= currentTime) {
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader,
"previously stored cookie was deleted");
CookieLogging::LogMessageToConsole(
aCRC, aHostURI, nsIScriptError::warningFlag,
CONSOLE_REJECTION_CATEGORY, "CookieRejectedExpired"_ns,
AutoTArray<nsString, 1>{
NS_ConvertUTF8toUTF16(aCookie->Name()),
});
NotifyChanged(oldCookie, u"deleted", oldCookieIsSession);
return;
}
@ -517,6 +543,12 @@ void CookieStorage::AddCookie(const nsACString& aBaseDomain,
if (aCookie->Expiry() <= currentTime) {
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader,
"cookie has already expired");
CookieLogging::LogMessageToConsole(
aCRC, aHostURI, nsIScriptError::warningFlag,
CONSOLE_REJECTION_CATEGORY, "CookieRejectedExpired"_ns,
AutoTArray<nsString, 1>{
NS_ConvertUTF8toUTF16(aCookie->Name()),
});
return;
}

View File

@ -112,7 +112,7 @@ class CookieStorage : public nsIObserver, public nsSupportsWeakReference {
void NotifyChanged(nsISupports* aSubject, const char16_t* aData,
bool aOldCookieIsSession = false);
void AddCookie(const nsACString& aBaseDomain,
void AddCookie(nsIConsoleReportCollector* aCRC, const nsACString& aBaseDomain,
const OriginAttributes& aOriginAttributes, Cookie* aCookie,
int64_t aCurrentTimeInUsec, nsIURI* aHostURI,
const nsACString& aCookieHeader, bool aFromHttp);

View File

@ -67,3 +67,23 @@ CookiePathOversize=Cookie “%1$S” is invalid because its path size is too big
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.
# LOCALIZATION NOTE (CookieRejectedByPermissionManager): %1$S is the cookie response header.
CookieRejectedByPermissionManager=Cookie “%1$S” has been rejected by user set permissions.
# LOCALIZATION NOTE (CookieRejectedInvalidCharName): %1$S is the cookie name.
CookieRejectedInvalidCharName=Cookie “%1$S” has been rejected for invalid characters in the name.
# LOCALIZATION NOTE (CookieRejectedInvalidDomain): %1$S is the cookie name.
CookieRejectedInvalidDomain=Cookie “%1$S” has been rejected for invalid domain.
# LOCALIZATION NOTE (CookieRejectedInvalidPrefix): %1$S is the cookie name.
CookieRejectedInvalidPrefix=Cookie “%1$S” has been rejected for invalid prefix.
# LOCALIZATION NOTE (CookieRejectedInvalidCharValue): %1$S is the cookie name.
CookieRejectedInvalidCharValue=Cookie “%1$S” has been rejected for invalid characters in the value.
# LOCALIZATION NOTE (CookieRejectedHttpOnlyButFromScript): %1$S is the cookie name.
CookieRejectedHttpOnlyButFromScript=Cookie “%1$S” has been rejected because there is already an HTTP-Only cookie but script tried to store a new one.
# LOCALIZATION NOTE (CookieRejectedSecureButHttp): %1$S is the cookie name.
CookieRejectedSecureButNonHttps=Cookie “%1$S” has been rejected because a non-HTTPS cookie can't be set as “secure”.
# LOCALIZATION NOTE (CookieRejectedThirdParty): %1$S is the cookie response header.
CookieRejectedThirdParty=Cookie “%1$S” has been rejected as third-party.
# LOCALIZATION NOTE (CookieRejectedNonsecureOverSecure): %1$S is the cookie name.
CookieRejectedNonsecureOverSecure=Cookie “%1$S” has been rejected because there is an existing “secure” cookie.
# LOCALIZATION NOTE (CookieRejectedExpired): %1$S is the cookie name.
CookieRejectedExpired=Cookie “%1$S” has been rejected because it is already expired.