Commit 7a09b52c authored by Daniel Gustafsson's avatar Daniel Gustafsson
Browse files

cookies: leave secure cookies alone



Only allow secure origins to be able to write cookies with the
'secure' flag set. This reduces the risk of non-secure origins
to influence the state of secure origins. This implements IETF
Internet-Draft draft-ietf-httpbis-cookie-alone-01 which updates
RFC6265.

Closes #2956
Reviewed-by: default avatarDaniel Stenberg <daniel@haxx.se>
parent fdc5563b
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -18,7 +18,9 @@
  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.
  published and details how cookies work within HTTP. In 2017, an update was
  [drafted](https://tools.ietf.org/html/draft-ietf-httpbis-cookie-alone-01)
  to deprecate modification of 'secure' cookies from non-secure origins.

## Cookies saved to disk

+0 −8
Original line number Diff line number Diff line
@@ -73,7 +73,6 @@
 5.5 auth= in URLs
 5.6 Refuse "downgrade" redirects
 5.7 QUIC
 5.8 Leave secure cookies alone

 6. TELNET
 6.1 ditch stdin
@@ -605,13 +604,6 @@
 implemented. This, to allow other projects to benefit from the work and to
 thus broaden the interest and chance of others to participate.

5.8 Leave secure cookies alone

 Non-secure origins (HTTP sites) should not be allowed to set or modify
 cookies with the 'secure' property:

 https://tools.ietf.org/html/draft-ietf-httpbis-cookie-alone-01


6. TELNET

+48 −7
Original line number Diff line number Diff line
@@ -433,9 +433,10 @@ Curl_cookie_add(struct Curl_easy *data,
                bool noexpire, /* if TRUE, skip remove_expired() */
                char *lineptr,   /* first character of the line */
                const char *domain, /* default domain */
                const char *path)   /* full path used when this cookie is set,
                const char *path,   /* full path used when this cookie is set,
                                       used to get default path for the cookie
                                       unless set */
                bool secure)  /* TRUE if connection is over secure origin */
{
  struct Cookie *clist;
  struct Cookie *co;
@@ -546,8 +547,20 @@ Curl_cookie_add(struct Curl_easy *data,
          /* this was a "<name>=" with no content, and we must allow
             'secure' and 'httponly' specified this weirdly */
          done = TRUE;
          if(strcasecompare("secure", name))
          /*
           * secure cookies are only allowed to be set when the connection is
           * using a secure protocol, or when the cookie is being set by
           * reading from file
           */
          if(strcasecompare("secure", name)) {
            if(secure || !c->running) {
              co->secure = TRUE;
            }
            else {
              badcookie = TRUE;
              break;
            }
          }
          else if(strcasecompare("httponly", name))
            co->httponly = TRUE;
          else if(sep)
@@ -831,7 +844,13 @@ Curl_cookie_add(struct Curl_easy *data,
        fields++; /* add a field and fall down to secure */
        /* FALLTHROUGH */
      case 3:
        co->secure = strcasecompare(ptr, "TRUE")?TRUE:FALSE;
        co->secure = FALSE;
        if(strcasecompare(ptr, "TRUE")) {
          if(secure || c->running)
            co->secure = TRUE;
          else
            badcookie = TRUE;
        }
        break;
      case 4:
        if(curlx_strtoofft(ptr, NULL, 10, &co->expires))
@@ -929,9 +948,31 @@ Curl_cookie_add(struct Curl_easy *data,
        /* the domains were identical */

        if(clist->spath && co->spath) {
          if(strcasecompare(clist->spath, co->spath)) {
            replace_old = TRUE;
          if(clist->secure && !co->secure) {
            size_t cllen;
            const char *sep;

            /*
             * A non-secure cookie may not overlay an existing secure cookie.
             * For an existing cookie "a" with path "/login", refuse a new
             * cookie "a" with for example path "/login/en", while the path
             * "/loginhelper" is ok.
             */

            sep = strchr(clist->spath + 1, '/');

            if(sep)
              cllen = sep - clist->spath;
            else
              cllen = strlen(clist->spath);

            if(strncasecompare(clist->spath, co->spath, cllen)) {
              freecookie(co);
              return NULL;
            }
          }
          else if(strcasecompare(clist->spath, co->spath))
            replace_old = TRUE;
          else
            replace_old = FALSE;
        }
@@ -1103,7 +1144,7 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
      while(*lineptr && ISBLANK(*lineptr))
        lineptr++;

      Curl_cookie_add(data, c, headerline, TRUE, lineptr, NULL, NULL);
      Curl_cookie_add(data, c, headerline, TRUE, lineptr, NULL, NULL, TRUE);
    }
    free(line); /* free the line buffer */
    remove_expired(c); /* run this once, not on every cookie */
+3 −2
Original line number Diff line number Diff line
@@ -7,7 +7,7 @@
 *                            | (__| |_| |  _ <| |___
 *                             \___|\___/|_| \_\_____|
 *
 * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
 * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
 *
 * This software is licensed as described in the file COPYING, which
 * you should have received as part of this distribution. The terms
@@ -85,7 +85,8 @@ struct Curl_easy;
struct Cookie *Curl_cookie_add(struct Curl_easy *data,
                               struct CookieInfo *, bool header, bool noexpiry,
                               char *lineptr,
                               const char *domain, const char *path);
                               const char *domain, const char *path,
                               bool secure);

struct Cookie *Curl_cookie_getlist(struct CookieInfo *, const char *,
                                   const char *, bool);
+3 −1
Original line number Diff line number Diff line
@@ -3873,7 +3873,9 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
                         here, or else use real peer host name. */
                      conn->allocptr.cookiehost?
                      conn->allocptr.cookiehost:conn->host.name,
                      data->state.up.path);
                      data->state.up.path,
                      (conn->handler->protocol&CURLPROTO_HTTPS)?
                      TRUE:FALSE);
      Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
    }
#endif
Loading