RESOLVED FIXED Bug 88760
[soup] Prevent setting or editing httpOnly cookies from JavaScript
https://bugs.webkit.org/show_bug.cgi?id=88760
Summary [soup] Prevent setting or editing httpOnly cookies from JavaScript
Chris Dumez
Reported 2012-06-11 00:20:54 PDT
Bug 86067 added http/tests/cookies/js-get-and-set-http-only-cookie.html test to make sure httpOnly cookies cannot be set, read or overwritten by JavaScript. This test is failing for both GTK and EFL ports because the Soup-specific code allows setting/overwriting httpOnly cookies from JavaScript.
Attachments
Patch (4.49 KB, patch)
2012-06-11 01:35 PDT, Chris Dumez
gustavo: review-
gustavo: commit-queue-
Patch (6.15 KB, patch)
2012-06-11 11:18 PDT, Chris Dumez
no flags
Patch (9.96 KB, patch)
2012-06-12 11:39 PDT, Chris Dumez
gustavo: review+
gustavo: commit-queue-
Patch (9.98 KB, patch)
2012-06-12 12:13 PDT, Chris Dumez
no flags
Chris Dumez
Comment 1 2012-06-11 01:35:26 PDT
Dominik Röttsches (drott)
Comment 2 2012-06-11 02:48:01 PDT
*** Bug 87247 has been marked as a duplicate of this bug. ***
jochen
Comment 3 2012-06-11 05:42:39 PDT
Comment on attachment 146809 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=146809&action=review > Source/WebCore/platform/network/soup/CookieJarSoup.cpp:-83 > - soup_cookie_jar_set_cookie_with_first_party(jar, origin.get(), firstParty.get(), value.utf8().data()); any reason for this change? It seems unrelated to the CL description
Chris Dumez
Comment 4 2012-06-11 05:46:54 PDT
Comment on attachment 146809 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=146809&action=review >> Source/WebCore/platform/network/soup/CookieJarSoup.cpp:-83 >> - soup_cookie_jar_set_cookie_with_first_party(jar, origin.get(), firstParty.get(), value.utf8().data()); > > any reason for this change? It seems unrelated to the CL description It has been replaced by soup_cookie_jar_add_cookie(jar, newCookie.release()) a few lines bellow since we already have the Cookie parsed. The first_party check is also done bellow.
Chris Dumez
Comment 5 2012-06-11 05:53:05 PDT
(In reply to comment #4) > (From update of attachment 146809 [details]) > View in context: https://bugs.webkit.org/attachment.cgi?id=146809&action=review > > >> Source/WebCore/platform/network/soup/CookieJarSoup.cpp:-83 > >> - soup_cookie_jar_set_cookie_with_first_party(jar, origin.get(), firstParty.get(), value.utf8().data()); > > > > any reason for this change? It seems unrelated to the CL description > > It has been replaced by soup_cookie_jar_add_cookie(jar, newCookie.release()) a few lines bellow since we already have the Cookie parsed. The first_party check is also done bellow. Otherwise soup_cookie_jar_set_cookie_with_first_party() will call internally: 1. soup_cookie_parse(); // Useless since we already did it 2. policy check; 3. soup_cookie_jar_add_cookie(); I'm now doing step 2 and 3 manually instead of calling soup_cookie_jar_set_cookie_with_first_party(), in order to an extra step 1. Hopefully, this is clearer.
jochen
Comment 6 2012-06-11 05:55:52 PDT
(In reply to comment #5) > (In reply to comment #4) > > (From update of attachment 146809 [details] [details]) > > View in context: https://bugs.webkit.org/attachment.cgi?id=146809&action=review > > > > >> Source/WebCore/platform/network/soup/CookieJarSoup.cpp:-83 > > >> - soup_cookie_jar_set_cookie_with_first_party(jar, origin.get(), firstParty.get(), value.utf8().data()); > > > > > > any reason for this change? It seems unrelated to the CL description > > > > It has been replaced by soup_cookie_jar_add_cookie(jar, newCookie.release()) a few lines bellow since we already have the Cookie parsed. The first_party check is also done bellow. > > Otherwise soup_cookie_jar_set_cookie_with_first_party() will call internally: > 1. soup_cookie_parse(); // Useless since we already did it > 2. policy check; > 3. soup_cookie_jar_add_cookie(); > > I'm now doing step 2 and 3 manually instead of calling soup_cookie_jar_set_cookie_with_first_party(), in order to an extra step 1. > > Hopefully, this is clearer. It seems unfortunate to duplicate the policy check code. I understand that you want to avoid parsing the cookie twice. But how can we make sure that the policy check here and in soup_cookie_jar_set_cookie_with_first_party do not diverge over time?
Chris Dumez
Comment 7 2012-06-11 06:08:00 PDT
(In reply to comment #6) > (In reply to comment #5) > > (In reply to comment #4) > > > (From update of attachment 146809 [details] [details] [details]) > > > View in context: https://bugs.webkit.org/attachment.cgi?id=146809&action=review > > > > > > >> Source/WebCore/platform/network/soup/CookieJarSoup.cpp:-83 > > > >> - soup_cookie_jar_set_cookie_with_first_party(jar, origin.get(), firstParty.get(), value.utf8().data()); > > > > > > > > any reason for this change? It seems unrelated to the CL description > > > > > > It has been replaced by soup_cookie_jar_add_cookie(jar, newCookie.release()) a few lines bellow since we already have the Cookie parsed. The first_party check is also done bellow. > > > > Otherwise soup_cookie_jar_set_cookie_with_first_party() will call internally: > > 1. soup_cookie_parse(); // Useless since we already did it > > 2. policy check; > > 3. soup_cookie_jar_add_cookie(); > > > > I'm now doing step 2 and 3 manually instead of calling soup_cookie_jar_set_cookie_with_first_party(), in order to an extra step 1. > > > > Hopefully, this is clearer. > > It seems unfortunate to duplicate the policy check code. I understand that you want to avoid parsing the cookie twice. But how can we make sure that the policy check here and in soup_cookie_jar_set_cookie_with_first_party do not diverge over time? kov/mrobinson: What's your preference? I don't really mind either way, it just seemed unfortunate to parse the Cookie twice.
Gustavo Noronha (kov)
Comment 8 2012-06-11 07:02:54 PDT
Comment on attachment 146809 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=146809&action=review > Source/WebCore/platform/network/soup/CookieJarSoup.cpp:82 > + GOwnPtr<SoupCookie> newCookie(soup_cookie_parse(value.utf8().data(), origin.get())); I think we may have a problem with API mismatch here. setCookies() implies value may contain more than one cookie, but all soup API we're using here only deals with the first cookie if there are many. We probably need a soup_cookie*s*_parse, and a soup_cookie_jar_set_cookie*s*_with_first_party(). > Source/WebCore/platform/network/soup/CookieJarSoup.cpp:87 > + // set from JavaScript (Bug 86067). I don't see value in mentioning this bug number in the code comments, the ChangeLog is enough. > Source/WebCore/platform/network/soup/CookieJarSoup.cpp:92 > + GOwnPtr<GSList> existingCookies(soup_cookie_jar_all_cookies(jar)); I think this is very inefficient, we should not be listing all cookies, how about using soup_cookie_jar_get_cookies(), so you can give it the URI? >>>>>> Source/WebCore/platform/network/soup/CookieJarSoup.cpp:-83 >>>>>> - soup_cookie_jar_set_cookie_with_first_party(jar, origin.get(), firstParty.get(), value.utf8().data()); >>>>> >>>>> any reason for this change? It seems unrelated to the CL description >>>> >>>> It has been replaced by soup_cookie_jar_add_cookie(jar, newCookie.release()) a few lines bellow since we already have the Cookie parsed. The first_party check is also done bellow. >>> >>> Otherwise soup_cookie_jar_set_cookie_with_first_party() will call internally: >>> 1. soup_cookie_parse(); // Useless since we already did it >>> 2. policy check; >>> 3. soup_cookie_jar_add_cookie(); >>> >>> I'm now doing step 2 and 3 manually instead of calling soup_cookie_jar_set_cookie_with_first_party(), in order to an extra step 1. >>> >>> Hopefully, this is clearer. >> >> It seems unfortunate to duplicate the policy check code. I understand that you want to avoid parsing the cookie twice. But how can we make sure that the policy check here and in soup_cookie_jar_set_cookie_with_first_party do not diverge over time? > > kov/mrobinson: What's your preference? I don't really mind either way, it just seemed unfortunate to parse the Cookie twice. I prefer reliability and readability in this case. Unless there's a performance issue we need to fix I don't think the loss in readability and the risk of diverging is paid by the gain in not parsing the cookie twice. If you want to make this more efficient I'd suggest proposing new API for soup to set a cookie from an existing SoupCookie object.
Chris Dumez
Comment 9 2012-06-11 07:53:14 PDT
Comment on attachment 146809 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=146809&action=review By the way, the "1 vs several" cookie parsing is a separate issue (which was already there). Should I open another bug for it and use the current bug report only for prevent httpOnly cookie setting from JS? >> Source/WebCore/platform/network/soup/CookieJarSoup.cpp:82 >> + GOwnPtr<SoupCookie> newCookie(soup_cookie_parse(value.utf8().data(), origin.get())); > > I think we may have a problem with API mismatch here. setCookies() implies value may contain more than one cookie, but all soup API we're using here only deals with the first cookie if there are many. We probably need a soup_cookie*s*_parse, and a soup_cookie_jar_set_cookie*s*_with_first_party(). Agreed. Unfortunately, those APIs do not exist in libsoup yet. >> Source/WebCore/platform/network/soup/CookieJarSoup.cpp:92 >> + GOwnPtr<GSList> existingCookies(soup_cookie_jar_all_cookies(jar)); > > I think this is very inefficient, we should not be listing all cookies, how about using soup_cookie_jar_get_cookies(), so you can give it the URI? Well, I considered that first but the issue is that soup_cookie_jar_get_cookies() returns the cookies in a single gchar*. Then, I have currently no way of parsing more than one cookie from a gchar*. >>>>>>> Source/WebCore/platform/network/soup/CookieJarSoup.cpp:-83 >>>>>>> - soup_cookie_jar_set_cookie_with_first_party(jar, origin.get(), firstParty.get(), value.utf8().data()); >>>>>> >>>>>> any reason for this change? It seems unrelated to the CL description >>>>> >>>>> It has been replaced by soup_cookie_jar_add_cookie(jar, newCookie.release()) a few lines bellow since we already have the Cookie parsed. The first_party check is also done bellow. >>>> >>>> Otherwise soup_cookie_jar_set_cookie_with_first_party() will call internally: >>>> 1. soup_cookie_parse(); // Useless since we already did it >>>> 2. policy check; >>>> 3. soup_cookie_jar_add_cookie(); >>>> >>>> I'm now doing step 2 and 3 manually instead of calling soup_cookie_jar_set_cookie_with_first_party(), in order to an extra step 1. >>>> >>>> Hopefully, this is clearer. >>> >>> It seems unfortunate to duplicate the policy check code. I understand that you want to avoid parsing the cookie twice. But how can we make sure that the policy check here and in soup_cookie_jar_set_cookie_with_first_party do not diverge over time? >> >> kov/mrobinson: What's your preference? I don't really mind either way, it just seemed unfortunate to parse the Cookie twice. > > I prefer reliability and readability in this case. Unless there's a performance issue we need to fix I don't think the loss in readability and the risk of diverging is paid by the gain in not parsing the cookie twice. If you want to make this more efficient I'd suggest proposing new API for soup to set a cookie from an existing SoupCookie object. Ok, I understand. I'll do that.
Chris Dumez
Comment 10 2012-06-11 10:48:55 PDT
Comment on attachment 146809 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=146809&action=review >>> Source/WebCore/platform/network/soup/CookieJarSoup.cpp:92 >>> + GOwnPtr<GSList> existingCookies(soup_cookie_jar_all_cookies(jar)); >> >> I think this is very inefficient, we should not be listing all cookies, how about using soup_cookie_jar_get_cookies(), so you can give it the URI? > > Well, I considered that first but the issue is that soup_cookie_jar_get_cookies() returns the cookies in a single gchar*. Then, I have currently no way of parsing more than one cookie from a gchar*. One other issue with soup_cookie_jar_get_cookies() is that it calls soup_cookie_to_cookie_header() for each cookie internally and not soup_cookie_to_set_cookie_header(). As a consequence, the returned cookies do not have a PATH set (only "NAME=VALUE"). However, I need the PATH (in addition to the NAME) in order to do an "overwrite" check.
Chris Dumez
Comment 11 2012-06-11 11:18:02 PDT
Created attachment 146878 [details] Patch Based on the feedback, I'm now proposing this patch. The patch now fixes setCookies() so that it processes all the cookies and not just the first one. I have clearly documented with FIXME comments the methods that should be removed later and provided by libsoup instead (optimally). However, I hope we can land this patch like this and improve the code later since this fixes a valid issue and getting a new and improved libsoup release may take time. I don't mind writing the patches for libsoup though if it helps.
Early Warning System Bot
Comment 12 2012-06-11 11:25:10 PDT
Gustavo Noronha (kov)
Comment 13 2012-06-11 11:39:46 PDT
(In reply to comment #9) > By the way, the "1 vs several" cookie parsing is a separate issue (which was already there). Should I open another bug for it and use the current bug report only for prevent httpOnly cookie setting from JS? Yes, please, I just thought I'd mention it so we can all be aware of the issue. > However, I hope we can land this patch like this and improve the code later since this fixes a valid issue and getting a new and improved libsoup release may take time. > I don't mind writing the patches for libsoup though if it helps. Like I said on IRC, I don't think there's a particular rush: we don't have any deadlines pressing us, and we can use our jhbuild infrastructure to bump the libsoup version as soon as new APIs are pushed. That said, if you want to go ahead I think your first patch is better than creating all those helper functions, modulo copying the policy check logic instead of calling soup's API we discussed.
Chris Dumez
Comment 14 2012-06-11 11:45:57 PDT
Comment on attachment 146878 [details] Patch Clearing flags. Will propose a new patch once libsoup is updated.
Chris Dumez
Comment 15 2012-06-12 01:32:57 PDT
Proposed the following libsoup patches to add the few API functions we need: https://bugzilla.gnome.org/show_bug.cgi?id=677922 https://bugzilla.gnome.org/show_bug.cgi?id=677923 I don't really think we need a new soup_cookies_parse() function in libsoup since we can split on newlines and call soup_cookie_parse() for each cookie. From libsoup point of view, such function makes little sense IMHO since it is not a header format (No "Set-Cookie:" or "Cookie:" at the beginning of the lines).
Mario Sanchez Prada
Comment 16 2012-06-12 03:14:12 PDT
Skipping http/tests/cookies/js-get-and-set-http-only-cookie.html in the GTK port: http://trac.webkit.org/changeset/120052 Please unskip when fixed. Thanks!
Chris Dumez
Comment 17 2012-06-12 11:39:14 PDT
Created attachment 147124 [details] Patch Updated patch now that the libsoup patches landed.
Gustavo Noronha (kov)
Comment 18 2012-06-12 11:55:20 PDT
Comment on attachment 147124 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=147124&action=review Since I have a small suggestion I'm not setting cq+, thanks, great work! > Source/WebCore/platform/network/soup/CookieJarSoup.cpp:75 > +static inline SoupCookie* findCookieInList(const GSList* cookies, const gchar* name, const gchar* path) I think you could make this helper contain the full logic, so instead of finding the cookie in the list and then verifying it's http-only at the caller you can instead have httpOnlyCookiExists(...). > Source/WebCore/platform/network/soup/CookieJarSoup.cpp:113 > + // Make sure we do not overwrite httpOnly cookies from JavaScript. > + SoupCookie* existingCookie = findCookieInList(existingCookies, soup_cookie_get_name(cookie.get()), soup_cookie_get_path(cookie.get())); > + if (existingCookie && soup_cookie_get_http_only(existingCookie)) > + continue; Would make this more readable =).
Chris Dumez
Comment 19 2012-06-12 12:13:32 PDT
Created attachment 147133 [details] Patch Take feedback into consideration. Could someone please cq+ ?
Gyuyoung Kim
Comment 20 2012-06-12 12:38:19 PDT
Chris Dumez
Comment 21 2012-06-12 12:41:08 PDT
Comment on attachment 147133 [details] Patch The ews efl did not take into consideration the libsoup update. False alarm. Marking as cq? again.
WebKit Review Bot
Comment 22 2012-06-12 17:33:21 PDT
Comment on attachment 147133 [details] Patch Clearing flags on attachment: 147133 Committed r120145: <http://trac.webkit.org/changeset/120145>
WebKit Review Bot
Comment 23 2012-06-12 17:33:27 PDT
All reviewed patches have been landed. Closing bug.
Sergio Villar Senin
Comment 24 2012-06-13 02:17:32 PDT
http/tests/misc/redirect-to-about-blank.html has started to fail after committing this.
Chris Dumez
Comment 25 2012-06-13 02:54:20 PDT
(In reply to comment #24) > http/tests/misc/redirect-to-about-blank.html has started to fail after committing this. Yes, I skipped the test for both GTK and EFL and I opened Bug 88961 to track the issue. This is caused by a regression in the new version of libsoup. It is actually unrelated to this fix but a side effect of the libsoup version bump in jhbuild.
Wajahat Siddiqui
Comment 26 2012-06-14 05:46:47 PDT
I am using a non jhbuild on ubuntu 12.04 to build webkit-gtk with options to autogen --enable-webkit2 && --with-gtk=3.0 and I get the following build error on svn rev# 120311 ../Source/WebCore/platform/network/soup/CookieJarSoup.cpp: In function ‘void WebCore::setCookies(WebCore::Document*, const WebCore::KURL&, const WTF::String&)’: ../Source/WebCore/platform/network/soup/CookieJarSoup.cpp:99:86: error: ‘soup_cookie_jar_get_cookie_list’ was not declared in this scope ../Source/WebCore/platform/network/soup/CookieJarSoup.cpp:117:92: error: ‘soup_cookie_jar_add_cookie_with_first_party’ was not declared in this scope I tried installing latest libsoup-2.39.2 but of no use, I could not find these APIs defined soup_cookie_jar_get_cookie_list & soup_cookie_jar_add_cookie_with_first_party in libsoup-2.39.2 Is something getting missed here?
Gustavo Noronha (kov)
Comment 27 2012-06-14 05:56:52 PDT
We're now using API from an unreleased version of soup. You need to build libsoup from git or wait for the next release.
Note You need to log in before you can comment on or make changes to this bug.