зеркало из https://github.com/mozilla/gecko-dev.git
prevent creating, modifying, and deleting HttpOnly cookies from web content, and add unit tests to that effect. b=383181, r+sr=dveditz
This commit is contained in:
Родитель
a7e74ff2ec
Коммит
c9d4ef4c68
|
@ -855,7 +855,7 @@ nsCookieService::SetCookieValue(nsIURI *aHostURI,
|
|||
attributes.isSecure = PR_FALSE;
|
||||
aHostURI->SchemeIs("https", &attributes.isSecure);
|
||||
|
||||
CheckAndAdd(aHostURI, aChannel, attributes, EmptyCString());
|
||||
CheckAndAdd(aHostURI, aChannel, attributes, EmptyCString(), PR_FALSE);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -874,7 +874,7 @@ nsCookieService::SetCookieString(nsIURI *aHostURI,
|
|||
httpInternal->GetDocumentURI(getter_AddRefs(firstURI));
|
||||
}
|
||||
|
||||
return SetCookieStringFromHttp(aHostURI, firstURI, aPrompt, aCookieHeader, nsnull, aChannel);
|
||||
return SetCookieStringInternal(aHostURI, firstURI, aPrompt, aCookieHeader, nsnull, aChannel, PR_FALSE);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -884,6 +884,18 @@ nsCookieService::SetCookieStringFromHttp(nsIURI *aHostURI,
|
|||
const char *aCookieHeader,
|
||||
const char *aServerTime,
|
||||
nsIChannel *aChannel)
|
||||
{
|
||||
return SetCookieStringInternal(aHostURI, aFirstURI, aPrompt, aCookieHeader, aServerTime, aChannel, PR_TRUE);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsCookieService::SetCookieStringInternal(nsIURI *aHostURI,
|
||||
nsIURI *aFirstURI,
|
||||
nsIPrompt *aPrompt,
|
||||
const char *aCookieHeader,
|
||||
const char *aServerTime,
|
||||
nsIChannel *aChannel,
|
||||
PRBool aFromHttp)
|
||||
{
|
||||
if (!aHostURI) {
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, nsnull, aCookieHeader, "host URI is null");
|
||||
|
@ -919,7 +931,7 @@ nsCookieService::SetCookieStringFromHttp(nsIURI *aHostURI,
|
|||
|
||||
// switch to a nice string type now, and process each cookie in the header
|
||||
nsDependentCString cookieHeader(aCookieHeader);
|
||||
while (SetCookieInternal(aHostURI, aChannel, cookieHeader, serverTime));
|
||||
while (SetCookieInternal(aHostURI, aChannel, cookieHeader, serverTime, aFromHttp));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -1030,7 +1042,7 @@ nsCookieService::Add(const nsACString &aDomain,
|
|||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
AddInternal(cookie, currentTimeInUsec / PR_USEC_PER_SEC, nsnull, nsnull);
|
||||
AddInternal(cookie, currentTimeInUsec / PR_USEC_PER_SEC, nsnull, nsnull, PR_TRUE);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -1284,7 +1296,8 @@ PRBool
|
|||
nsCookieService::SetCookieInternal(nsIURI *aHostURI,
|
||||
nsIChannel *aChannel,
|
||||
nsDependentCString &aCookieHeader,
|
||||
PRInt64 aServerTime)
|
||||
PRInt64 aServerTime,
|
||||
PRBool aFromHttp)
|
||||
{
|
||||
// create a stack-based nsCookieAttributes, to store all the
|
||||
// attributes parsed from the cookie
|
||||
|
@ -1309,7 +1322,7 @@ nsCookieService::SetCookieInternal(nsIURI *aHostURI,
|
|||
cookieAttributes.isSession = GetExpiry(cookieAttributes, aServerTime,
|
||||
currentTimeInUsec / PR_USEC_PER_SEC);
|
||||
|
||||
CheckAndAdd(aHostURI, aChannel, cookieAttributes, savedCookieHeader);
|
||||
CheckAndAdd(aHostURI, aChannel, cookieAttributes, savedCookieHeader, aFromHttp);
|
||||
|
||||
return newCookie;
|
||||
}
|
||||
|
@ -1318,7 +1331,8 @@ void
|
|||
nsCookieService::CheckAndAdd(nsIURI *aHostURI,
|
||||
nsIChannel *aChannel,
|
||||
nsCookieAttributes &aAttributes,
|
||||
const nsAFlatCString &aCookieHeader)
|
||||
const nsAFlatCString &aCookieHeader,
|
||||
PRBool aFromHttp)
|
||||
{
|
||||
// reject cookie if it's over the size limit, per RFC2109
|
||||
if ((aAttributes.name.Length() + aAttributes.value.Length()) > kMaxBytesPerCookie) {
|
||||
|
@ -1381,7 +1395,7 @@ nsCookieService::CheckAndAdd(nsIURI *aHostURI,
|
|||
|
||||
// add the cookie to the list. AddInternal() takes care of logging.
|
||||
// we get the current time again here, since it may have changed during prompting
|
||||
AddInternal(cookie, PR_Now() / PR_USEC_PER_SEC, aHostURI, aCookieHeader.get());
|
||||
AddInternal(cookie, PR_Now() / PR_USEC_PER_SEC, aHostURI, aCookieHeader.get(), aFromHttp);
|
||||
}
|
||||
|
||||
// this is a backend function for adding a cookie to the list, via SetCookie.
|
||||
|
@ -1393,7 +1407,8 @@ void
|
|||
nsCookieService::AddInternal(nsCookie *aCookie,
|
||||
PRInt64 aCurrentTime,
|
||||
nsIURI *aHostURI,
|
||||
const char *aCookieHeader)
|
||||
const char *aCookieHeader,
|
||||
PRBool aFromHttp)
|
||||
{
|
||||
// start a transaction on the storage db, to optimize deletions/insertions.
|
||||
// transaction will automically commit on completion. if we already have a
|
||||
|
@ -1407,6 +1422,13 @@ nsCookieService::AddInternal(nsCookie *aCookie,
|
|||
nsRefPtr<nsCookie> oldCookie;
|
||||
if (foundCookie) {
|
||||
oldCookie = matchIter.current;
|
||||
|
||||
// if the old cookie is httponly, make sure we're not coming from script
|
||||
if (!aFromHttp && oldCookie->IsHttpOnly()) {
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader, "previously stored cookie is httponly; coming from script");
|
||||
return;
|
||||
}
|
||||
|
||||
RemoveCookieFromList(matchIter);
|
||||
|
||||
// check if the cookie has expired
|
||||
|
@ -1423,6 +1445,12 @@ nsCookieService::AddInternal(nsCookie *aCookie,
|
|||
return;
|
||||
}
|
||||
|
||||
// if the new cookie is httponly, make sure we're not coming from script
|
||||
if (!aFromHttp && aCookie->IsHttpOnly()) {
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader, "cookie is httponly; coming from script");
|
||||
return;
|
||||
}
|
||||
|
||||
// check if we have to delete an old cookie.
|
||||
nsEnumerationData data(aCurrentTime, LL_MAXINT);
|
||||
if (CountCookiesFromHostInternal(aCookie->RawHost(), data) >= mMaxCookiesPerHost) {
|
||||
|
|
|
@ -171,9 +171,10 @@ class nsCookieService : public nsICookieServiceInternal
|
|||
nsresult Read();
|
||||
void GetCookieList(nsIURI *aHostURI, nsIURI *aFirstURI, nsIChannel *aChannel, const nsACString *aName, PRBool isHttpBound, nsAutoVoidArray &aResult);
|
||||
char* CookieStringFromArray(const nsAutoVoidArray& aCookieList, nsIURI *aHostURI);
|
||||
PRBool SetCookieInternal(nsIURI *aHostURI, nsIChannel *aChannel, nsDependentCString &aCookieHeader, PRInt64 aServerTime);
|
||||
void CheckAndAdd(nsIURI *aHostURI, nsIChannel *aChannel, nsCookieAttributes &aAttributes, const nsAFlatCString &aCookieHeader);
|
||||
void AddInternal(nsCookie *aCookie, PRInt64 aCurrentTime, nsIURI *aHostURI, const char *aCookieHeader);
|
||||
nsresult SetCookieStringInternal(nsIURI *aHostURI, nsIURI *aFirstURI, nsIPrompt *aPrompt, const char *aCookieHeader, const char *aServerTime, nsIChannel *aChannel, PRBool aFromHttp);
|
||||
PRBool SetCookieInternal(nsIURI *aHostURI, nsIChannel *aChannel, nsDependentCString &aCookieHeader, PRInt64 aServerTime, PRBool aFromHttp);
|
||||
void CheckAndAdd(nsIURI *aHostURI, nsIChannel *aChannel, nsCookieAttributes &aAttributes, const nsAFlatCString &aCookieHeader, PRBool aFromHttp);
|
||||
void AddInternal(nsCookie *aCookie, PRInt64 aCurrentTime, nsIURI *aHostURI, const char *aCookieHeader, PRBool aFromHttp);
|
||||
void RemoveCookieFromList(nsListIter &aIter);
|
||||
PRBool AddCookieToList(nsCookie *aCookie, PRBool aWriteToDB = PR_TRUE);
|
||||
static PRBool GetTokenValue(nsASingleFragmentCString::const_char_iterator &aIter, nsASingleFragmentCString::const_char_iterator &aEndIter, nsDependentCSubstring &aTokenString, nsDependentCSubstring &aTokenValue, PRBool &aEqualsFound);
|
||||
|
|
|
@ -642,19 +642,47 @@ main(PRInt32 argc, char *argv[])
|
|||
GetACookie(cookieService, "http://multi.path.tests/one/two/three/four/five/six/", nsnull, getter_Copies(cookie));
|
||||
rv[0] = CheckResult(cookie.get(), MUST_EQUAL, "test7=path; test6=path; test3=path; test1=path; test5=path; test4=path; test2=path; test8=path");
|
||||
|
||||
allTestsPassed = PrintResult(rv, 1) && allTestsPassed;
|
||||
|
||||
|
||||
// *** httponly tests
|
||||
printf("*** Beginning httponly tests...\n");
|
||||
|
||||
// Since this cookie is NOT set via http, setting it fails
|
||||
SetACookieNoHttp(cookieService, "http://httponly.test/", "test=httponly; httponly");
|
||||
GetACookie(cookieService, "http://httponly.test/", nsnull, getter_Copies(cookie));
|
||||
rv[0] = CheckResult(cookie.get(), MUST_BE_NULL);
|
||||
// Since this cookie is set via http, it can be retrieved
|
||||
SetACookie(cookieService, "http://httponly.test/", nsnull, "test=httponly; httponly", nsnull);
|
||||
GetACookie(cookieService, "http://httponly.test/", nsnull, getter_Copies(cookie));
|
||||
rv[0] = CheckResult(cookie.get(), MUST_EQUAL, "test=httponly");
|
||||
// Since this cookie is NOT set via http, it can NOT be retrieved
|
||||
SetACookieNoHttp(cookieService, "http://httponly.test/", "test=httponly; httponly");
|
||||
rv[1] = CheckResult(cookie.get(), MUST_EQUAL, "test=httponly");
|
||||
// ... but not by web content
|
||||
GetACookieNoHttp(cookieService, "http://httponly.test/", getter_Copies(cookie));
|
||||
rv[1] = CheckResult(cookie.get(), MUST_NOT_EQUAL, "test=httponly");
|
||||
rv[2] = CheckResult(cookie.get(), MUST_BE_NULL);
|
||||
// Non-Http cookies should not replace HttpOnly cookies
|
||||
SetACookie(cookieService, "http://httponly.test/", nsnull, "test=httponly; httponly", nsnull);
|
||||
SetACookieNoHttp(cookieService, "http://httponly.test/", "test=not-httponly");
|
||||
GetACookie(cookieService, "http://httponly.test/", nsnull, getter_Copies(cookie));
|
||||
rv[3] = CheckResult(cookie.get(), MUST_EQUAL, "test=httponly");
|
||||
// ... and, if an HttpOnly cookie already exists, should not be set at all
|
||||
GetACookieNoHttp(cookieService, "http://httponly.test/", getter_Copies(cookie));
|
||||
rv[4] = CheckResult(cookie.get(), MUST_BE_NULL);
|
||||
// Non-Http cookies should not delete HttpOnly cookies
|
||||
SetACookie(cookieService, "http://httponly.test/", nsnull, "test=httponly; httponly", nsnull);
|
||||
SetACookieNoHttp(cookieService, "http://httponly.test/", "test=httponly; max-age=-1");
|
||||
GetACookie(cookieService, "http://httponly.test/", nsnull, getter_Copies(cookie));
|
||||
rv[5] = CheckResult(cookie.get(), MUST_EQUAL, "test=httponly");
|
||||
// ... but HttpOnly cookies should
|
||||
SetACookie(cookieService, "http://httponly.test/", nsnull, "test=httponly; httponly; max-age=-1", nsnull);
|
||||
GetACookie(cookieService, "http://httponly.test/", nsnull, getter_Copies(cookie));
|
||||
rv[6] = CheckResult(cookie.get(), MUST_BE_NULL);
|
||||
// Non-Httponly cookies can replace HttpOnly cookies when set over http
|
||||
SetACookie(cookieService, "http://httponly.test/", nsnull, "test=httponly; httponly", nsnull);
|
||||
SetACookie(cookieService, "http://httponly.test/", nsnull, "test=not-httponly", nsnull);
|
||||
GetACookieNoHttp(cookieService, "http://httponly.test/", getter_Copies(cookie));
|
||||
rv[7] = CheckResult(cookie.get(), MUST_EQUAL, "test=not-httponly");
|
||||
|
||||
allTestsPassed = PrintResult(rv, 2) && allTestsPassed;
|
||||
allTestsPassed = PrintResult(rv, 8) && allTestsPassed;
|
||||
|
||||
|
||||
// *** nsICookieManager{2} interface tests
|
||||
|
|
Загрузка…
Ссылка в новой задаче