diff --git a/CHANGES b/CHANGES index 6039fd6ed4..02a476c0f1 100644 --- a/CHANGES +++ b/CHANGES @@ -7,6 +7,14 @@ Changelog Daniel S (31 Jan 2008) +- Niklas Angebrand made the cookie support in libcurl properly deal with the + "HttpOnly" feature introduced by Microsoft and apparently also supported by + Firefox: http://msdn2.microsoft.com/en-us/library/ms533046.aspx . HttpOnly + is now supported when received from servers in HTTP headers, when written to + cookie jars and when read from existing cookie jars. + + I modified test case 31 and 46 to also do some basic HttpOnly testing. + - Dmitry Kurochkin moved several struct fields from the connectdata struct to the SingleRequest one to make pipelining better. It is a bit tricky to keep them in the right place, to keep things related to the actual request or to diff --git a/RELEASE-NOTES b/RELEASE-NOTES index b8eabdb921..9c590e55d5 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -10,7 +10,7 @@ Curl and libcurl 7.18.1 This release includes the following changes: - o + o added support for HttpOnly cookies This release includes the following bugfixes: @@ -31,6 +31,6 @@ New curl mirrors: This release would not have looked like this without help, code, reports and advice from friends like these: - Michal Marek, Dmitry Kurochkin + Michal Marek, Dmitry Kurochkin, Niklas Angebrand Thanks! (and sorry if I forgot to mention someone) diff --git a/lib/cookie.c b/lib/cookie.c index 3e6c8a1cd8..f2dabd8e20 100644 --- a/lib/cookie.c +++ b/lib/cookie.c @@ -367,8 +367,12 @@ Curl_cookie_add(struct SessionHandle *data, else { if(sscanf(ptr, "%" MAX_COOKIE_LINE_TXT "[^;\r\n]", what)) { - if(strequal("secure", what)) + if(strequal("secure", what)) { co->secure = TRUE; + } + else if (strequal("httponly", what)) { + co->httponly = TRUE; + } /* else, unsupported keyword without assign! */ @@ -433,6 +437,19 @@ Curl_cookie_add(struct SessionHandle *data, char *tok_buf; int fields; + /* IE introduced HTTP-only cookies to prevent XSS attacks. Cookies + marked with httpOnly after the domain name are not accessible + from javascripts, but since curl does not operate at javascript + level, we include them anyway. In Firefox's cookie files, these + lines are preceeded with #HttpOnly_ and then everything is + as usual, so we skip 10 characters of the line.. + */ + if (strncmp(lineptr, "#HttpOnly_", 10) == 0) { + lineptr += 10; + co->httponly = TRUE; + } + + if(lineptr[0]=='#') { /* don't even try the comments */ free(co); @@ -918,6 +935,7 @@ void Curl_cookie_cleanup(struct CookieInfo *c) static char *get_netscape_format(const struct Cookie *co) { return aprintf( + "%s" /* httponly preamble */ "%s%s\t" /* domain */ "%s\t" /* tailmatch */ "%s\t" /* path */ @@ -925,6 +943,7 @@ static char *get_netscape_format(const struct Cookie *co) "%" FORMAT_OFF_T "\t" /* expires */ "%s\t" /* name */ "%s", /* value */ + co->httponly?"#HttpOnly_":"", /* Make sure all domains are prefixed with a dot if they allow tailmatching. This is Mozilla-style. */ (co->tailmatch && co->domain && co->domain[0] != '.')? ".":"", diff --git a/lib/cookie.h b/lib/cookie.h index 7fbc72e8a0..a1d107352c 100644 --- a/lib/cookie.h +++ b/lib/cookie.h @@ -50,6 +50,7 @@ struct Cookie { bool secure; /* whether the 'secure' keyword was used */ bool livecookie; /* updated from a server, not a stored file */ + bool httponly; /* true if the httponly directive is present */ }; struct CookieInfo { diff --git a/tests/data/test31 b/tests/data/test31 index a0a9ce9b04..444a9b13e3 100644 --- a/tests/data/test31 +++ b/tests/data/test31 @@ -26,6 +26,7 @@ Set-Cookie: nodomain=value; expires=Fri Feb 2 11:56:27 GMT 2035 Set-Cookie: novalue; domain=reallysilly Set-Cookie: test=yes; domain=foo.com; expires=Sat Feb 2 11:56:27 GMT 2030 Set-Cookie: test2=yes; domain=se; expires=Sat Feb 2 11:56:27 GMT 2030 +Set-Cookie: magic=yessir; path=/silly/; HttpOnly boo @@ -69,6 +70,7 @@ Accept: */* .127.0.0.1 TRUE /silly/ FALSE 0 ismatch this .127.0.0.1 TRUE / FALSE 0 partmatch present 127.0.0.1 FALSE /we/want/ FALSE 2054030187 nodomain value +#HttpOnly_127.0.0.1 FALSE /silly/ FALSE 0 magic yessir diff --git a/tests/data/test46 b/tests/data/test46 index bc08219042..56ad859587 100644 --- a/tests/data/test46 +++ b/tests/data/test46 @@ -51,6 +51,7 @@ TZ=GMT www.fake.come FALSE / FALSE 1022144953 cookiecliente si www.loser.com FALSE / FALSE 1139150993 UID 99 %HOSTIP FALSE / FALSE 1439150993 mooo indeed +#HttpOnly_%HOSTIP FALSE / FALSE 1439150993 mooo2 indeed2 %HOSTIP FALSE / FALSE 0 empty @@ -64,7 +65,7 @@ www.loser.com FALSE / FALSE 1139150993 UID 99 GET /want/46 HTTP/1.1 Host: %HOSTIP:%HTTPPORT Accept: */* -Cookie: empty=; mooo=indeed +Cookie: empty=; mooo2=indeed2; mooo=indeed @@ -75,6 +76,7 @@ Cookie: empty=; mooo=indeed www.fake.come FALSE / FALSE 1022144953 cookiecliente si www.loser.com FALSE / FALSE 1139150993 UID 99 %HOSTIP FALSE / FALSE 1439150993 mooo indeed +#HttpOnly_%HOSTIP FALSE / FALSE 1439150993 mooo2 indeed2 %HOSTIP FALSE / FALSE 0 empty %HOSTIP FALSE / FALSE 2054030187 ckyPersistent permanent %HOSTIP FALSE / FALSE 0 ckySession temporary