Bug 10957

Summary: HttpOnly Cookie Option
Product: WebKit Reporter: Robert Sesek <rsesek>
Component: WebKit Misc.Assignee: Darin Adler <darin>
Status: RESOLVED FIXED    
Severity: Enhancement CC: abarth, ap, collinj, darin, jim, priyajeet.hora, sam
Priority: P2 Keywords: InRadar
Version: 420+Flags: ddkilzer: CloneForRadar+
Hardware: Mac   
OS: OS X 10.4   
URL: http://msdn.microsoft.com/workshop/author/dhtml/httponly_cookies.asp
Attachments:
Description Flags
test case (for http/tests/security)
none
patch; someone needs to help me make more regression tests
none
patch ap: review+

Description Robert Sesek 2006-09-20 17:25:34 PDT
In the web development arena, HttpOnly cookies have become quite the buzz. It basically disallows JavaScript access to a cookie when it is sent with the HttpOnly flag. Currently only IE supports it, but Firefox is looking into it. I think it'd be very helpful to have (especially since PHP 5.2 will now support it--meaning lots of developers will use it). I've linked to Microsoft's spec on the flag.
Comment 1 Alexey Proskuryakov 2006-09-20 21:51:19 PDT
Mozilla bug: <https://bugzilla.mozilla.org/show_bug.cgi?id=178993>.
Comment 2 Alexey Proskuryakov 2007-12-11 08:28:42 PST
This is now implemented in Firefox 2 and Opera 9.5.

This looks like a pretty important feature to me, but we need support from underlying system frameworks to implement it. A request to add such support is tracked by <rdar://problem/4154226>.
Comment 3 Alexey Proskuryakov 2007-12-11 08:30:33 PST
Created attachment 17845 [details]
test case (for http/tests/security)
Comment 4 David Kilzer (:ddkilzer) 2007-12-12 06:19:28 PST
<rdar://problem/5642992>
Comment 5 Jim Manico 2008-03-25 23:28:33 PDT
Safari is the last browser to lack HttpOnly support.  I for one think it's a critical need to bring Safari's browser security in line with the rest of the industry.
Comment 6 Jim Manico 2008-03-27 18:47:04 PDT
(from Robert)

The problem isn't entirely with WebKit itself, but with the underlying implementation of HTTP. Safari uses CFNetwork on the mac to parse HTTP headers into objects. Unfortunately, this code isn't public, and it's this code that needs to be changed in order for HTTPOnly to be implemented. While preventing DOM/JavaScript access to cookies needs to be done in the WebKit source, until the underlying network implementation is updated to parse the HTTPOnly flag, there's no way this is possible.

So in short, Apple is blocking this bug from being fixed. Once they update CFNetwork, progress on this patch can be made. Until then, no dice. I recommend you file a bug in RadarWeb if you're interested in getting HTTPOnly/CFNetwork done.
Comment 7 Alexey Proskuryakov 2008-03-27 23:52:03 PDT
As mentioned above, there is already a Radar bug filed about this (which was closed as a duplicate of <rdar://problem/4154226>). As always, you are welcome to file another bug, citing your specific use case; please include this original bug number if you decide to file it, to ensure that it is handled right when screening.
Comment 8 Jim Manico 2008-03-28 01:01:20 PDT
(In reply to comment #7)
> As mentioned above, there is already a Radar bug filed about this (which was
> closed as a duplicate of <rdar://problem/4154226>). As always, you are welcome
> to file another bug, citing your specific use case; please include this
> original bug number if you decide to file it, to ensure that it is handled
> right when screening.
> 

Alex, my apologies. I'm not certain how to access rdar://problem/5642992 - is there an Internet facing URL for this problem, or is rdar for Apple employees only?

Comment 9 Alexey Proskuryakov 2008-03-28 01:36:57 PDT
The latter is correct - it's only accessible to Apple folks.
Comment 10 Jim Manico 2008-03-28 10:11:50 PDT
So, a closed source proprietary library is blocking an open source project from adding a key security feature that the rest of the browser industry supports? I smell a rat. It might be at rdar but it sure sounds "off the radar" to me.
Comment 11 Robert Sesek 2008-04-01 05:55:32 PDT
Apple isn't the only company we're waiting on to get HttpOnly support. Qt/Trolltech is also lacking HttpOnly support in QNetworkCookie. I filed bug #205188 with them to get QNetworkCookie::isHttpOnly() added.
Comment 12 Jim Manico 2008-04-01 22:58:56 PDT
Robert, thank you very kindly for taking to time to submit a bug to Qt/Trolltech.
Comment 13 Robert Sesek 2008-04-07 06:24:16 PDT
Here's the public issue for Qt: http://trolltech.com/developer/task-tracker/index_html?id=206125&method=entry
Comment 14 Jim Manico 2008-05-22 12:33:59 PDT
The Java EE Servlet 3.0 spec now includes support for the HttpOnly cookie. This is just more evidence that HttpOnly is becoming a widespread non-MS standard and is worthy of Safari support. 
Comment 15 Darin Adler 2008-05-22 12:35:37 PDT
It should definitely be supported by Safari!

I'm not sure why having a WebKit bug report open for this is helpful, though. It's not something handled by WebKit, and adding this to the CFNetwork library used on Mac OS X won't require any WebKit code changes.
Comment 16 Jim Manico 2008-05-22 12:40:57 PDT
Thank you Darin! I'm grateful that someone at Apple agrees that we need HttpOnly support in Safari. Safari is the last holdout - Opera, IE and FireFox all support HttpOnly!

Will the trolltech issue posted in comment #13 cover this issue? Of is there another place we can post a bug?
Comment 17 Darin Adler 2008-05-22 12:43:38 PDT
(In reply to comment #16)
> Thank you Darin! I'm grateful that someone at Apple agrees that we need
> HttpOnly support in Safari. Safari is the last holdout - Opera, IE and FireFox
> all support HttpOnly!
> 
> Will the trolltech issue posted in comment #13 cover this issue? Of is there
> another place we can post a bug?

It's actually comment #7 that covers the Safari issue. What Alexey said is exactly right.
Comment 18 Robert Sesek 2008-05-22 13:13:56 PDT
(In reply to comment #15)
> I'm not sure why having a WebKit bug report open for this is helpful, though.
> It's not something handled by WebKit, and adding this to the CFNetwork library
> used on Mac OS X won't require any WebKit code changes.

I think a code change to the WebCore/platform still needs to be made. Looking at the various CookieJar classes, it looks like it will be up to WebCore to disregard HttpOnly cookies -- they will still be passed to us from the underlying network layer. So I do think this bug needs to be open; however, maybe the component should be changed to WebCore?

(In reply to comment #16)
> Will the trolltech issue posted in comment #13 cover this issue? Of is there
> another place we can post a bug?

Trolltech fixed this for the upcoming v4.5 of Qt. I'm currently working on compiling Qt and testing a patch I have made for the Qt-backed WebKit.
Comment 19 Darin Adler 2008-05-22 13:20:33 PDT
(In reply to comment #18)
> I think a code change to the WebCore/platform still needs to be made. Looking
> at the various CookieJar classes, it looks like it will be up to WebCore to
> disregard HttpOnly cookies -- they will still be passed to us from the
> underlying network layer.

I see. You're right -- it might turn out that way. Another design would be to have HttpOnly cookies entirely invisible to the old API and add new API that allows clients to see them. I guess we won't know what's required until this gets implemented by the networking layer.
Comment 20 Robert Sesek 2008-05-22 13:51:33 PDT
(In reply to comment #19)
> (In reply to comment #18)
> > I think a code change to the WebCore/platform still needs to be made. Looking
> > at the various CookieJar classes, it looks like it will be up to WebCore to
> > disregard HttpOnly cookies -- they will still be passed to us from the
> > underlying network layer.
> 
> I see. You're right -- it might turn out that way. Another design would be to
> have HttpOnly cookies entirely invisible to the old API and add new API that
> allows clients to see them. I guess we won't know what's required until this
> gets implemented by the networking layer.
> 

Looking at Qt's implementation in the 4.5 snapshot, you get all the cookies and then have to call isHttpOnly() on QNetworkCookie to figure out whether or not you keep it in the CookieJar.
Comment 21 Alexey Proskuryakov 2008-07-07 22:15:57 PDT
Something else that will need to be done at WebCore level is filtering out HttpOnly cookies from XMLHttpRequest getResponseHeader results.
Comment 22 Alexey Proskuryakov 2008-07-07 22:17:02 PDT
See also: https://bugzilla.mozilla.org/show_bug.cgi?id=380418
Comment 23 Jim Manico 2008-07-08 12:38:15 PDT
http://www.owasp.org/index.php/HTTPOnly is also a great reference. Complete implementation includes read and write prevention though document.cookie, as well prevention of reading or writing the session cookie via a XMLHTTPRequest.
Comment 24 Jim Manico 2008-07-08 12:39:19 PDT
Let me correct that:

http://www.owasp.org/index.php/HTTPOnly is also a great reference. Complete
implementation includes read and write prevention of HttpOnly cookies though document.cookie, as well as prevention of reading or writing HttpOnly cookies via a XMLHTTPRequest.
Comment 25 Darin Adler 2008-11-17 09:38:30 PST
(In reply to comment #24)
> http://www.owasp.org/index.php/HTTPOnly is also a great reference. Complete
> implementation includes read and write prevention of HttpOnly cookies though
> document.cookie, as well as prevention of reading or writing HttpOnly cookies
> via a XMLHTTPRequest.

That page doesn't mention prevention of writing HttpOnly cookies vis XMLHttpRequest. Should that really be prevented? Does any browser currently do that?
Comment 26 Darin Adler 2008-11-17 10:19:33 PST
Created attachment 25220 [details]
patch; someone needs to help me make more regression tests
Comment 27 Darin Adler 2008-11-17 10:21:22 PST
Loose ends that need to be resolved:

    1) include test cases in the patch
    2) figure out how to compile the CFNetwork version
    3) [optional] add implementations for other platforms that have HTTP-only support in the networking layers (e.g. Qt)
Comment 28 Darin Adler 2008-11-17 12:25:17 PST
Created attachment 25222 [details]
patch

Windows side is not compiled or tested yet.
Comment 29 Jim Manico 2008-11-17 18:03:12 PST
Sorry, my mistake.

I was referring to preventing XMLHTTPRequest access to set-cookie and set-cookie2 response headers - for HTTPOnly cookies.

There is no need to prevent write prevention via XMLHTTPRequest response headers. (no such thing) 
Comment 30 Jim Manico 2008-11-17 18:08:12 PST
Actually, the HttpOnly RFC working group says:

When the server sends a Set-Cookie or Set-Cookie2 header with the HTTPOnly flag set, the client should:

(1) Prevent client-side scripts from reading Cookie or Cookie2 values
(2) Prevent client-side scripts from writing Cookie or Cookie2 values
(3) Prevent client-side scripts from reading Set-Cookie or Set-Cookie2 response headers (via XHR)
(4) Prevent client-side scripts from writing Cookie or Cookie2 request headers (via XHR)

Let me get more info and post back asap.
Comment 31 Adam Barth 2008-11-17 18:47:23 PST
> Actually, the HttpOnly RFC working group says:

It would be useful to test the behavior of Firefox and Internet Explorer to make sure we have identical semantics.

In some sense, it is impossible to prevent writes because the script could always exhaust the browser's cookie store and then add a new non-HTTPOnly versions of the cookie.
Comment 32 Jim Manico 2008-11-17 20:03:38 PST
> In some sense, it is impossible to prevent writes because the script could
> always exhaust the browser's cookie store and then add a new non-HTTPOnly
> versions of the cookie.

(From Bill Cory)

That is an interesting problem.  They're referring to the hard limit that governs the number of cookies a site can have stored on the browser -- there's a limit to prevent a malicious site from filling up your hard drive with numerous cookies.  So for most browsers, the limit is 20 cookies max, and when a browser receives cookie #21, it will discard the least used (or oldest?).  This talks a bit about it:

	http://www.cookiecentral.com/faq/#2.5

So if an attacker sets 20 cookies, they can force the HTTPOnly-protected cookie out of the cookie store, then set a non-HTTPOnly cookie.

It would be tempting to change the browser behavior to NOT bump out existing cookies when the cookie store is full, but that would then allow an attacker to populate the store with bogus cookies, and wouldn't allow the legitimate website to set any additional cookies (a cookie DoS attack of sorts).  Of course, the server could just iterate through the cookies and cause the bogus ones to expire, but it's not ideal.

One solution might be that HTTPOnly cookies can't be bumped out of the cookie store.  Another solution might be that the Cookie header sent to the server somehow identifies the cookies that are HTTPOnly, which would allow the server to detect tampering (or two headers, one for regular cookies and one for HTTPOnly cookies).

Or other ideas?

The spec should probably state that the HTTPOnly flag can only be set by the server via a Set-Cookie or Set-Cookie2 header -- scripts are not allowed to set the flag or modify the incoming Set-Cookie/2 header.
Comment 33 Adam Barth 2008-11-17 21:47:26 PST
> (From Bill Cory)

I really wouldn't be that concerned about it.  Secure cookies have all the same problems and IMHO are more critical to secure.  Playing with the eviction strategy is very fragile and hard to get right.  Altering the Cookie header is unlikely to succeed (there have already been several failed attempts for Secure cookies).  In any case, it's not clear to me what attack you're trying to prevent.
Comment 34 Alexey Proskuryakov 2008-11-18 06:04:46 PST
Comment on attachment 25222 [details]
patch

> -    // <rdar://problem/5632883> On 10.5, NSHTTPCookieStorage would happily store an empty cookie, which would be sent as "Cookie: =".
> +    // <rdar://problem/5632883> On 10.5, NSHTTPCookieStorage would happily store an empty cookie,

You removed "happily" elsewhere, but not here :-)

> Index: WebCore/platform/network/soup/CookieJarSoup.h
> +#include <wtf/Platform.h>

Why is this include needed? I think that we rely on cpp files to include config.h, which includes Platform.h.

> +    return reinterpret_cast<IsHTTPOnlyFunction>(GetProcAddress(GetModuleHandleA("CFNetwork"), "CFHTTPCookieIsHTTPOnly"));

Just to confirm: weak linking doesn't work with MSVC and/or CFNetwork.dll, correct?

> +    frame->domWindow()->console()->addMessage(JSMessageSource, ErrorMessageLevel, message, 1, String());

I really wish we could get rid of these source-less error messages everywhere, but this patch is obviously not when it should be done.

> +    if (isSetCookieHeader(name) && !document()->securityOrigin()->canLoadLocalResources()) {
> +        reportUnsafeUsage(document(), "Refused to get unsafe header \"" + name + "\"");

I think this could have a comment explaining why we are doing this (which is that we need to filter out HTTPOnly cookies, but that's hard, and Firefox trunk also doesn't try to). Similarly, it may be better to explicitly test for HTTPOnly cookies being hidden from XHR, or at least to explain that some failures of the test are not catastrophic.

r=me, assuming this builds and works on Windows.
Comment 35 Darin Adler 2008-11-18 09:23:31 PST
(In reply to comment #34)
> You removed "happily" elsewhere, but not here :-)

Will do.

> > Index: WebCore/platform/network/soup/CookieJarSoup.h
> > +#include <wtf/Platform.h>
> 
> Why is this include needed? I think that we rely on cpp files to include
> config.h, which includes Platform.h.

I guess it's not.

> > +    return reinterpret_cast<IsHTTPOnlyFunction>(GetProcAddress(GetModuleHandleA("CFNetwork"), "CFHTTPCookieIsHTTPOnly"));
> 
> Just to confirm: weak linking doesn't work with MSVC and/or CFNetwork.dll,
> correct?

Weak linking might work, but it's more complicated to get that right with project files changes and such, so I'd prefer to do it this way.

> > +    frame->domWindow()->console()->addMessage(JSMessageSource, ErrorMessageLevel, message, 1, String());
> 
> I really wish we could get rid of these source-less error messages everywhere,
> but this patch is obviously not when it should be done.

I'd love to hear more about how to fix that.

> > +    if (isSetCookieHeader(name) && !document()->securityOrigin()->canLoadLocalResources()) {
> > +        reportUnsafeUsage(document(), "Refused to get unsafe header \"" + name + "\"");
> 
> I think this could have a comment explaining why we are doing this (which is
> that we need to filter out HTTPOnly cookies, but that's hard, and Firefox trunk
> also doesn't try to). Similarly, it may be better to explicitly test for
> HTTPOnly cookies being hidden from XHR, or at least to explain that some
> failures of the test are not catastrophic.

I believe that hiding the Set-Cookie header field entirely is a design decision and not just a compromise. I don't think we'd want to undo this later even if someone donated code to filter out the HTTP-only cookies. However, I'm not an expert in this area, so perhaps my belief is wrong.
Comment 36 Darin Adler 2008-11-18 09:27:57 PST
(In reply to comment #30)
> (1) Prevent client-side scripts from reading Cookie or Cookie2 values
> (2) Prevent client-side scripts from writing Cookie or Cookie2 values

Roughly speaking, I believe these are prevented by the changes my patch makes to the CookieJar implementations for the Foundation and CFNetwork networking layers. Other ports will have to do similar changes.

> (3) Prevent client-side scripts from reading Set-Cookie or Set-Cookie2 response
> headers (via XHR)

This is prevented by code added to XMLHttpRequest in my patch.

> (4) Prevent client-side scripts from writing Cookie or Cookie2 request headers
> (via XHR)

This was already impossible with TOT WebKit because those header field names are not on the white list in isSafeRequestHeader.
Comment 37 Alexey Proskuryakov 2008-11-18 09:32:43 PST
> I believe that hiding the Set-Cookie header field entirely is a design decision
> and not just a compromise. I don't think we'd want to undo this later even if
> someone donated code to filter out the HTTP-only cookies.

What worries me is that nothing (apart from svn log) will speak about the rationale for this behavior - neither code comments, not tests, really. I do not have an opinion on whether this is a final solution (more likely, it is).
Comment 38 Darin Adler 2008-11-18 09:35:02 PST
(In reply to comment #37)
> What worries me is that nothing (apart from svn log) will speak about the
> rationale for this behavior - neither code comments, not tests, really. I do
> not have an opinion on whether this is a final solution (more likely, it is).

Oh, sorry, I wasn't clear. I do intend to add a comment based on your remarks!
Comment 39 Darin Adler 2008-11-18 10:49:55 PST
http://trac.webkit.org/changeset/38566

We can use new separate bugs to track any problems with the implementation. Testing the Mac port and CFNetwork-based Windows port implementation will be limited to people with the new CFNetwork version on their computer.
Comment 40 Jim Manico 2008-11-18 21:15:10 PST
> In any case, it's not clear to me what attack you're trying to
> prevent.

(From Bil Cory)

Cookie eviction allows an attacker to remove legitimate cookies, it also allows an attacker to replace legitimate cookies with their own -- most useful for session fixation attacks.

If only a server can create HTTPOnly cookies, and HTTPOnly cookies can never be evicted, then it would prevent a cookie eviction attack.  The cookie will still expire at some point, or the server can update the cookie to remove the HTTPOnly flag, and/or set the cookie to immediately expire, so control over the cookie is kept with the server.
Comment 41 Jim Manico 2008-12-21 05:14:46 PST
Can you please make sure your patch includes protection from both Set-Cookie and Set-Cookie2 per the suggestion of the HTTPOnly working group document, entry A-2? http://docs.google.com/View?docid=dxxqgkd_0cvcqhsdw

-- (WebCore::XMLHttpRequest::getAllResponseHeaders): Hide Set-Cookie headers from
 28 clients that don't have local-resource privileges.
++ (WebCore::XMLHttpRequest::getAllResponseHeaders): Hide Set-Cookie and Set-Cookie2 headers, in a case insensitive way, from 28 clients that don't have local-resource privileges.
Comment 42 Darin Adler 2008-12-21 10:01:54 PST
(In reply to comment #41)
> Can you please make sure your patch includes protection from both Set-Cookie
> and Set-Cookie2 per the suggestion of the HTTPOnly working group document,
> entry A-2?

Jim, I'm not sure what "make sure" means in your request. The patch does include what you're asking for. The patch is <http://trac.webkit.org/changeset/38566>. A relevant function is:

    static bool isSetCookieHeader(const String& name)
    {
        return equalIgnoringCase(name, "set-cookie") || equalIgnoringCase(name, "set-cookie2"); 
    } 

Is there something specific you're worried about?
Comment 43 Jim Manico 2008-12-21 23:12:44 PST
> Jim, I'm not sure what "make sure" means in your request.

The code you submitted covers that request. I was looking at what I think are just the function comments, which did not seem to address set-cookie2 

(WebCore::XMLHttpRequest::getAllResponseHeaders): Hide Set-Cookie headers
from 28 clients that don't have local-resource privileges.

Sorry for the hassle.

Comment 44 Michael Gilbert 2009-04-26 15:24:18 PDT
Hello, we are looking at whether we need to adopt these patches in debian stable, which includes webkit 1.0.1 dated 2008-06-15; well before revision 38566.  Looking at the code, it looks like these fixes primarily apply to the windows- and mac-specific cookie handling with some clean-up of the libsoup code (but nothing soup-related specifically fixed).

Note that the version of webkit in stable does not make use of libsoup, so does that mean that it is falling back on the windows-specific cookie handling?  Note also that this version appears to pass the regression test attached.

Also, could libsoup itself be vulnerable to these problems, and if so have there any patches been issued?

Please let me know if you think that we need to adopt these patches.