From e6522522f96ad96b459e608c6cdcd46a32099b5b Mon Sep 17 00:00:00 2001 From: Daniel Gustafsson Date: Sun, 17 Feb 2019 00:09:30 +0100 Subject: cookie: Add support for cookie prefixes The draft-ietf-httpbis-rfc6265bis-02 draft, specify a set of prefixes and how they should affect cookie initialization, which has been adopted by the major browsers. This adds support for the two prefixes defined, __Host- and __Secure, and updates the testcase with the supplied examples from the draft. Closes #3554 Reviewed-by: Daniel Stenberg --- docs/HTTP-COOKIES.md | 11 +++++++++-- docs/ROADMAP.md | 10 ---------- lib/cookie.c | 38 ++++++++++++++++++++++++++++++++++++++ lib/cookie.h | 10 +++++++++- tests/data/test1561 | 20 ++++++++++++++++++++ 5 files changed, 76 insertions(+), 13 deletions(-) diff --git a/docs/HTTP-COOKIES.md b/docs/HTTP-COOKIES.md index 66e39d232..632cb4ebe 100644 --- a/docs/HTTP-COOKIES.md +++ b/docs/HTTP-COOKIES.md @@ -18,9 +18,16 @@ original [Netscape spec from 1994](https://curl.haxx.se/rfc/cookie_spec.html). In 2011, [RFC6265](https://www.ietf.org/rfc/rfc6265.txt) was finally - published and details how cookies work within HTTP. In 2017, an update was + published and details how cookies work within HTTP. In 2016, an update which + added support for prefixes was + [proposed](https://tools.ietf.org/html/draft-ietf-httpbis-cookie-prefixes-00), + and in 2017, another update was [drafted](https://tools.ietf.org/html/draft-ietf-httpbis-cookie-alone-01) - to deprecate modification of 'secure' cookies from non-secure origins. + to deprecate modification of 'secure' cookies from non-secure origins. Both + of these drafs have been incorporated into a proposal to + [replace](https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-02) + RFC6265. Cookie prefixes and secure cookie modification protection has been + implemented by curl. ## Cookies saved to disk diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 497c45b54..cbcaa2235 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -10,16 +10,6 @@ QUIC See the [QUIC wiki page](https://github.com/curl/curl/wiki/QUIC). -HTTP cookies ------------- - -On top of what we already support, the prefix cookie draft has been adopted by -the httpwg in IETF and we should support it as the popular browsers will: - -[Cookie Prefixes](https://tools.ietf.org/html/draft-ietf-httpbis-cookie-prefixes-00) - -[Firefox bug report about secure cookies](https://bugzilla.mozilla.org/show_bug.cgi?id=976073) - SRV records ----------- diff --git a/lib/cookie.c b/lib/cookie.c index 4fb992ac9..3a3f45de3 100644 --- a/lib/cookie.c +++ b/lib/cookie.c @@ -528,6 +528,19 @@ Curl_cookie_add(struct Curl_easy *data, while(*whatptr && ISBLANK(*whatptr)) whatptr++; + /* + * Check if we have a reserved prefix set before anything else, as we + * otherwise have to test for the prefix in both the cookie name and + * "the rest". Prefixes must start with '__' and end with a '-', so + * only test for names where that can possibly be true. + */ + if(nlen > 3 && name[0] == '_' && name[1] == '_') { + if(strncasecompare("__Secure-", name, 9)) + co->prefix |= COOKIE_PREFIX__SECURE; + else if(strncasecompare("__Host-", name, 7)) + co->prefix |= COOKIE_PREFIX__HOST; + } + if(!co->name) { /* The very first name/value pair is the actual cookie name */ if(!sep) { @@ -862,6 +875,11 @@ Curl_cookie_add(struct Curl_easy *data, co->name = strdup(ptr); if(!co->name) badcookie = TRUE; + /* For Netscape file format cookies we check prefix on the name */ + if(strncasecompare("__Secure-", co->name, 9)) + co->prefix |= COOKIE_PREFIX__SECURE; + else if(strncasecompare("__Host-", co->name, 7)) + co->prefix |= COOKIE_PREFIX__HOST; break; case 6: co->value = strdup(ptr); @@ -890,6 +908,26 @@ Curl_cookie_add(struct Curl_easy *data, } + if(co->prefix & COOKIE_PREFIX__SECURE) { + /* The __Secure- prefix only requires that the cookie be set secure */ + if(!co->secure) { + freecookie(co); + return NULL; + } + } + if(co->prefix & COOKIE_PREFIX__HOST) { + /* + * The __Host- prefix requires the cookie to be secure, have a "/" path + * and not have a domain set. + */ + if(co->secure && co->path && strcmp(co->path, "/") == 0 && !co->tailmatch) + ; + else { + freecookie(co); + return NULL; + } + } + if(!c->running && /* read from a file */ c->newsession && /* clean session cookies */ !co->expires) { /* this is a session cookie since it doesn't expire! */ diff --git a/lib/cookie.h b/lib/cookie.h index 3ee457c62..b2730cfb9 100644 --- a/lib/cookie.h +++ b/lib/cookie.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -44,8 +44,16 @@ struct Cookie { bool livecookie; /* updated from a server, not a stored file */ bool httponly; /* true if the httponly directive is present */ int creationtime; /* time when the cookie was written */ + unsigned char prefix; /* bitmap fields indicating which prefix are set */ }; +/* + * Available cookie prefixes, as defined in + * draft-ietf-httpbis-rfc6265bis-02 + */ +#define COOKIE_PREFIX__SECURE (1<<0) +#define COOKIE_PREFIX__HOST (1<<1) + #define COOKIE_HASH_SIZE 256 struct CookieInfo { diff --git a/tests/data/test1561 b/tests/data/test1561 index ff448c95f..69352fda2 100644 --- a/tests/data/test1561 +++ b/tests/data/test1561 @@ -18,6 +18,15 @@ Date: Thu, 09 Nov 2010 14:49:00 GMT Server: test-server/fake Set-Cookie: super=secret; domain=example.com; path=/1561; secure; Set-Cookie: supersuper=secret; domain=example.com; path=/1561/login/; secure; +Set-Cookie: __Secure-SID=12345; Domain=example.com +Set-Cookie: __Secure-SID=12346; Secure; Domain=example.com +Set-Cookie: supersupersuper=secret; __Secure-SID=12346; Secure; Domain=example.com +Set-Cookie: __Host-SID=22345 +Set-Cookie: __Host-SID=22346; Secure +Set-Cookie: __Host-SID=22347; Domain=example.com +Set-Cookie: __Host-SID=22348; Domain=example.com; Path=/ +Set-Cookie: __Host-SID=22349; Secure; Domain=example.com; Path=/ +Set-Cookie: __Host-SID=12346; Secure; Path=/ Content-Length: 7 nomnom @@ -33,6 +42,14 @@ Set-Cookie: public=yes; domain=example.com; path=/foo; Set-Cookie: supersuper=secret; domain=example.com; path=/1561/login/en; Set-Cookie: supersuper=secret; domain=example.com; path=/1561/login; Set-Cookie: secureoverhttp=yes; domain=example.com; path=/1561; secure; +Set-Cookie: __Secure-SID=22345; Domain=example.com +Set-Cookie: __Secure-SID=22346; Secure; Domain=example.com +Set-Cookie: __Host-SID=32345 +Set-Cookie: __Host-SID=32346; Secure +Set-Cookie: __Host-SID=32347; Domain=example.com +Set-Cookie: __Host-SID=32348; Domain=example.com; Path=/ +Set-Cookie: __Host-SID=32349; Secure; Domain=example.com; Path=/ +Set-Cookie: __Host-SID=32350; Secure; Path=/ Content-Length: 7 nomnom @@ -77,6 +94,9 @@ Accept: */* # This file was generated by libcurl! Edit at your own risk. .example.com TRUE /foo FALSE 0 public yes +www.example.com FALSE / TRUE 0 __Host-SID 12346 +.example.com TRUE / TRUE 0 supersupersuper secret +.example.com TRUE / TRUE 0 __Secure-SID 12346 .example.com TRUE /1561/login/ TRUE 0 supersuper secret #HttpOnly_.example.com TRUE /15 FALSE 0 super secret -- cgit v1.2.1