Subject: Cookies and schemes.

From: Mike West <[email-masked]>
Date: Mon, 9 Mar 2020 09:51:46 +0100

Hey folks!

We've known for quite some time that cookies' lack of respect for the
scheme that created them was an unfortunate choice that means cookies can
give only weak guarantees of confidentiality
<https://tools.ietf.org/html/rfc6265#section-8.5>. We further know that
long-lived non-secure cookies create real risks for users (pervasive
monitoring, data safety, etc).

Martin Thomson's https://tools.ietf.org/html/draft-thomson-http-omnomnom-00 is
one take on an approach to mitigating these risks.
https://github.com/mikewest/cookies-over-http-bad is another. Neither took
off when they were proposed, but they seem to me to be clearly good ideas,
at least directionally. Given the state of the world today, and the
significant migration from HTTP to HTTPS we've seen in the past few years,
I'd like to try tilting at this particular windmill again:

https://github.com/mikewest/scheming-cookies proposes two changes:

1. We teach cookies about schemes, and lock them to the scheme that set
them (just like every other web-facing storage mechanism).

2. We curtail non-secure schemes' cookies' lifetime by agreeing on a set of
heuristics for a user's "session" on a given site, and culling cookies when
a site's session expires.

The explainer tries to work through each of those and their implications in
a little more detail. I'd appreciate feedback, either here or in the GitHub
repo. :)

-mike

---

From: Willy Tarreau <[email-masked]>
Date: Mon, 9 Mar 2020 14:00:29 +0100

Hi Mike,

> a little more detail. I'd appreciate feedback, either here or in the GitHub

What I'm seeing there sounds reasonable to me. The main use I know for
cookies in clear text is for server stickiness. These ones are exclusively
session cookies (no expiration date so that they're never stored). With
browsers now staying open forever, these ones are sometimes problematic
(i.e. many users sticking to a single server after a domino effect) and
I've found myself having to artificially implement timeouts in their
values to be able to ignore too old cookies.

If we would implement a limitation to the lifetime of a session cookie,
it would solve this but would create a new problem which is that sessions
would be limited in time, which is not the same as limiting the idle time
as you don't want to break a session being used. What we need is a way to
let the client inform the server that it'd rather refresh the cookie if
it really wants the client to continue to present it (this is what we do
in haproxy as the expiration time is provided in the value so that we can
decide to drop it or update it). Or instead of forcing a limited lifetime
on session cookies in cleartext, we could force a limited idle time, which
more closely matches the real problem (i.e. users not aware they're passing
such info).

Regarding the scheme, there is a use case for cookies passed from HTTP
to HTTPS which is also to ensure the user can stick to the same server
when switching to HTTPS. But given that it's just for a short transition
it could make sense to address it exactly like the other one above, as a
session cookie only and with a much shorter lifetime.

One point worth mentioning is that while there are tons of legacy applications
outthere making use of cookies, I tend to think that nowadays most of them
are placed behind reverse-proxies for various reasons including performance,
security, integration, support for newer protocols, and that most of the
remaining legitimate clear-text cookies are really used by infrastructure
components such as load balancers, which are usually kept reasonably up
to date and can be reconfigured to adapt to an evolving ecosystem. In
addition I'm not aware of any valid use case of stored cookies learned
over cleartext connections.

While typing this I'm thinking that most of the cookies I'm seeing in
requests don't come from servers themselves but are set from javascript
components. Maybe we could already have browsers ask for user's consent
before setting a cookie from JS on a cleartext page ? And maybe also
before sending a stored cookie on such a page ? That would be a nice
way to get sites to progressively apply some cleanups and remove part
or all of their useless trackers.

It would also make sense to enforce shorter names+values for cleartext
cookies: if a server stores a lot of info in a cleartext cookie, then
there definitely is a problem and most likely it's not by design but
rather a mistake. Keeping only up to 16 chars for the name and 16 for
the value looks quite enough for a servername and various deliberate
use cases (infrastructure paths).

Just my two cents,
Willy

---

From: "Martin Thomson" <[email-masked]>
Date: Tue, 10 Mar 2020 09:02:25 +1100

> them (just like every other web-facing storage mechanism).

Excellent!

To Willy's point about transfer, perhaps we can allow any cookies that are set on an http:// response to follow a redirect to https://  The Sec-Nonsecure-Cookie header field seems like it might not be great long term.

Tf the goal is to support temporally-constrained transfer, then binding the cookies to the redirect avoids pulling from previous state.  Also, the redirector could have just packed this information into the target URL, so it's not a new tracking vector.

Have I missed a key piece of information?  Willy, could this work in the cases you understand?

> 2. We curtail non-secure schemes' cookies' lifetime by agreeing on a 
> set of heuristics for a user's "session" on a given site, and culling 
> cookies when a site's session expires.

Also good.  The need for heuristics is unfortunate, but I appreciate that you have to do that.

---

From: Willy Tarreau <[email-masked]>
Date: Tue, 10 Mar 2020 04:39:57 +0100

On Tue, Mar 10, 2020 at 09:02:25AM +1100, Martin Thomson wrote:
> To Willy's point about transfer, perhaps we can allow any cookies that are set on an http:// response to follow a redirect to https://

Maybe that can work.

>  The Sec-Nonsecure-Cookie header field seems like it might not be great long term.

I don't believe in adding attributes to legacy applications anyway. If they
rely on older mechanisms it's because they cannot be changed, and it's not
by changing default behavior that we'll make them suddenly capable of adapting
their code to emit new cookie attributes.

> Tf the goal is to support temporally-constrained transfer, then binding the
> cookies to the redirect avoids pulling from previous state.  Also, the
> redirector could have just packed this information into the target URL, so
> it's not a new tracking vector.

Absolutely.

> Have I missed a key piece of information?  Willy, could this work in the

I think it can, yes, but it would still require some infrastructure
adaptations, and by default could degrade the behavior over HTTPS by
forcing to always append a cookie in response. The typical case I'm
thinking about is the following sequence:

  1) client connects over HTTP to example.com
  2) the load balancer doesn't find a cookie, applies the load balancing
     algorithm and forwards the request to server #1
  3) server responds, load balancer appends cookie "SERVER=srv01" to the
     response
  4) client makes a few more HTTP requests presenting "SERVER=srv01",
     which the LB spots and continues to pass to server #1. Since the
     client presents the cookie, the LB doesn't append it on new responses.
  5) one such response is now a 302, client then sends a request over
     HTTPS, still presenting the cookie "SERVER=srv01". The load balancer
     sees it and forwards it to the server and doesn't append it on response.

Past this point, if the client stops presenting the cookie, we'll lose the
binding. I'm still not clear on how to address this without systematically
appending a cookie to responses, which is bad. We're exactly in the situation
where I was thinking that it would be nice to have the ability for the client
to signal the server "I'm going to expire this cookie, please renew it if
still needed".

Maybe the right approach would be to change the default behavior with a
new attribute. Currently without any attribute the cookie is presented
to both schemes, while with the secure attribute it's presented only to
HTTPS. By having an explicit such as "secure-and-insecure" or something
like this, we could have load balancers explicitly set this one for
server affinity, and let the client present it to both HTTP and HTTPS.
Then with this, we could stop presenting an HTTP-learned cookie over
HTTPS at all by default.

Just my two cents,
Willy

---

From: Mike West <[email-masked]>
Date: Tue, 10 Mar 2020 08:29:50 +0100

Thanks, Martin and Willy!

On Mon, Mar 9, 2020 at 11:07 PM Martin Thomson <[email-masked]> wrote:

> To Willy's point about transfer, perhaps we can allow any cookies that are
> set on an http:// response to follow a redirect to https://  The
> Sec-Nonsecure-Cookie header field seems like it might not be great long
> term.
>

The `Sec-Nonsecure-Cookie` header is, indeed, not something we'd want to
keep for the long term. I'm thinking of it explicitly as a stopgap for the
period of time directly after we start enforcing scheme bindings, and would
expect it to live for a quarter or so. That said, I'm not amazingly
enthusiastic about it, but it has three properties I like:

1.  It gives secure hosts access to their non-secure cookies in a way that
allows them to perform a migration if they so desire.
2.  It does not put those cookies into the `Cookie` header, meaning that a
host that doesn't intentionally perform a migration (and, in the best case,
validate the data against whatever securely-delivered state it has access
to before blindly accepting it) won't be at risk.
3.  It doesn't require us to figure out an ordering of "the same" cookie
that's distinguished only by scheme (e.g. `Set-Cookie: a=b` on both `
http://example.com/` and `https://example.com`).

If I understand the redirect proposed above, it would give network
attackers the ability to send arbitrary cookies to secure servers by
forging HTTP responses that set cookies and redirect to HTTPS. I'd like to
remain robust against this kind of attack.

Two alternatives come to mind:

1.  Perhaps we do this kind of thing only for a specific endpoint
(`/.well-known/migrate-nonsecure-cookies`, for example)?
2.  Perhaps we prefix the non-secure cookie names with `__Non-secure-`
rather than minting a new header?

Both would require more explicit involvement from the server to perform the
migration, which I think is valuable.

> Also good.  The need for heuristics is unfortunate, but I appreciate that

The heuristic described in the doc seems workable, and matches my
intuitions about user's understanding of session lifetimes (modulo a lot of
fuzziness around the exact time period after closing the last window). I
hope it's something that's deployable in practice.

> thinking about is the following sequence:

For clarity, my goal is to encourage developers who require stateful
connections to use HTTPS, and to make it more difficult to persist data
outside of a secure context.

With that in mind, I'm not enthusiastic about creating long-lived
mechanisms to deal with hybrid sites that try to span both HTTP and HTTPS
connections. This proposal (in combination with +Steven Bingler
<[email-masked]>'s schemeful same-site proposal
<https://github.com/mikewest/cookie-incrementalism/pull/3>) suggests that `
http://example.com/` and `https://example.com/` are not actually the same
site, and shouldn't be privileged with regard to each other. That seems
like the right place to land, and I'd like to ensure that the changes we
make to the platform lead in that direction towards a future in which:

1.  HTTP sites have, at most, session-based cookies as per the heuristics
described above
<https://github.com/mikewest/scheming-cookies#cookies-lifetime>.
2.  HTTPS sites have persistent cookies.
3.  Never the twain shall meet.

Ideally, the load-balancing case devolves to the LB doing an immediate
redirect to HTTPS, and then deciding which backend the user should stick to
in that secure context. I don't think we should add new attributes in order
to support sites that push users back and forth from HTTPS to HTTP.

Thanks!

-mike

---

From: "Martin Thomson" <[email-masked]>
Date: Tue, 10 Mar 2020 18:51:09 +1100

> (`/.well-known/migrate-nonsecure-cookies`, for example)?

Eww.  More seriously, I can't see this fitting with existing needs very well.

> rather than minting a new header?

That might work.  It's new mechanisms, but not new-header-field new mechanisms.  More below.

> redirect to HTTPS, and then deciding which backend the user should 
> stick to in that secure context. I don't think we should add new 
> attributes in order to support sites that push users back and forth 
> from HTTPS to HTTP.

Yes. HSTS is the only path that has long-term legs here.  If port 80 wants to do some setup for port 443, that's not terrible, but ultimately I think we need to have servers prepared for the first connection arriving on 443.

I'd like to understand more of why there might be multiple cleartext redirects involved.  Or why it might be desirable to not include cookies in all of those responses.

To that end, anything we do here will apparently cause immediate bustage, with the possible exception of what I proposed (absent multiple redirects being involved).

You might annotate those with tags that indicate their shaky status as a warning, but I expect that anything that isn't bustage will be roundly ignored.  So moving them, either by changing their name or putting them in a new header field, does have the effect of causing sites to pay attention.  But flat-out removing the cookies would also have a similar effect and that is the end goal.

The only value to moving them is that maybe servers can salvage something from this quickly and without a ton of extra engineering.  I think that the prefix is the most likely to be conducive to some form of salvage, but I would want to hear that this is necessary and easy before we get into a multi-stage deprecation process.

---

From: David Benjamin <[email-masked]>
Date: Tue, 10 Mar 2020 12:25:04 -0400

On Tue, Mar 10, 2020 at 3:55 AM Martin Thomson <[email-masked]> wrote:

> Yes. HSTS is the only path that has long-term legs here.  If port 80 wants
> to do some setup for port 443, that's not terrible, but ultimately I think
> we need to have servers prepared for the first connection arriving on 443.
>

I'm not sure if, by HSTS, you mean that sites should stick to HTTPS or if
you mean the actual HSTS header. Sites certainly should stop mixing HTTP
and HTTPS, and once they've done that, HSTS is a good thing to deploy. But
I think we should aim to make HSTS less load-bearing. Today HSTS is a
more-or-less frontline defense against all the various cookie mistakes
around partitioning HTTP and HTTPS. This is awkward because HSTS is
stateful and thus a possible tracking vector
<https://webkit.org/blog/8146/protecting-against-hsts-abuse/>, but
mitigations against that risk breaking that defense. If we can bring
cookies closer to the standard origin-based isolation in the rest of the
web, HSTS is no longer needed as a patch for cookies. The remaining use
cases (making sure you are on the correct origin to begin with, and
stricter certificate errors) primarily affect top-level navigations and are
thus more amenable to ideas like
https://github.com/mikewest/strict-navigation-security.

> I'd like to understand more of why there might be multiple cleartext
> redirects involved.  Or why it might be desirable to not include cookies in
> all of those responses.
>
> To that end, anything we do here will apparently cause immediate bustage,
> with the possible exception of what I proposed (absent multiple redirects
> being involved).
>
> You might annotate those with tags that indicate their shaky status as a
> warning, but I expect that anything that isn't bustage will be roundly
> ignored.  So moving them, either by changing their name or putting them in
> a new header field, does have the effect of causing sites to pay
> attention.  But flat-out removing the cookies would also have a similar
> effect and that is the end goal.
>
> The only value to moving them is that maybe servers can salvage something
> from this quickly and without a ton of extra engineering.  I think that the
> prefix is the most likely to be conducive to some form of salvage, but I
> would want to hear that this is necessary and easy before we get into a
> multi-stage deprecation process.
>

I see two plausible reasons to want to add some kind of cross-scheme
carveout:
1. as you allude to, providing a low-effort intermediate state for
(insecure) mixed-HTTP/HTTPS sites that would take longer to finish their
HTTPS migration
2. preserving state when an (insecure) fully-HTTP site migrates to HTTPS

On (1), the intermediate state is added fuss because the affected sites
which take advantage of it still need to do the work to migrate to HTTPS.
It also is a risk that we'll be stuck in that intermediate state. Thus I
think it is only valuable if we can get to the intermediate state faster
and the intermediate state is useful in itself. For it to be useful, I
think it needs to be robust against attackers. I'm thus not excited about
anything which keys on redirects because redirects can be faked by the
network. Today, cookies are insecure by default and opt-in secure (if you
use both the Secure attribute and the __Secure- prefix). I think a good
intermediate state would be secure by default and opt-out secure (whether
we spell the opt-out __Non-secure- or Sec-Nonsecure-Cookie or whatever is I
think mostly about the "low-effort" goal, as long as it actually
functions[*] as an opt-out). Then after sufficient time has passed to
reasonably expect a full HTTPS migration, we remove that opt-out, meeting
standard security requirements of the web platform. (Or rather something
closer to it. We'd still have port and eTLD+1 silliness.)

On (2), the thinking would be that sites shouldn't be disincentivized from
migrating from HTTP to HTTPS out of worry of losing all their state. Such a
site might then use the above opt-in path as a one-time migration and then
stop consuming the insecure values after the migration is done. Of course,
they'll do the former but never do the latter, which is why this can't be
there forever. The question then is when would we be okay removing this. I
think that's where the cookie lifetime change fits in. Given that http://
is pronounced "the network", it is not a suitable scope for long-term
state, thus it makes sense to tie the lifetime to some notion of
session—just long enough that the user can still perform continuous actions
to avoid breaking everything. If that sticks, there won't be meaningful
state to migrate to HTTPS in the first place and the need for (2) is
reduced.

David

[*] An example of something which doesn't actually function as an opt-out
would be an Insecure attribute to mirror the existing Secure attribute.
That helps with HTTPS-to-HTTP leaks but it provides no defense against
HTTP-to-HTTPS injection because the network can add that attribute all they
like.

---

From: Spencer Dawkins at IETF <[email-masked]>
Date: Tue, 10 Mar 2020 12:58:41 -0500

A minor comment on this exchange:

> That might work.  It's new mechanisms, but not new-header-field new

I'm not an expert at this, but think I'm following the discussion in this
thread.

Is "Non-secure" the best term that could be used as a prefix? ISTM that
part of the game here may be shaming people into not continuing to use this
mechanism for months/years/ever, and "secure/non-secure" seems an awfully
overloaded term. Could the prefix be more precise about what's at stake if
you continue to use it?

Random example unlikely to be the best suggestion: compare the shame of
__Non-secure to the shame of __Trivially-Hijackable, if that's the case,
and it's the worst accurate thing you can think of. If not, please
substitute the worst possible accurate characterization.

Make good choices, of course.

Best,

Spencer

---

From: Willy Tarreau <[email-masked]>
Date: Tue, 10 Mar 2020 21:51:05 +0100

On Tue, Mar 10, 2020 at 08:29:50AM +0100, Mike West wrote:
> keep for the long term.

We've already seen the mess created by set-cookie2, please don't suggest
doing the same again! It would be hard to retrofit into existing components
and it will always result in a hack. It's worth mentioning that all the crap
we have to live with were created as quick and dirty solutions to a problem.
Even the set-cookie header field by the way, specified in 2 or 3 paragraphs
only.

> I'm thinking of it explicitly as a stopgap for the

It will be worse. Those having trouble configuring them will modify their
LBs to put everything into cookie and systematically duplicate them into
the other ones, considering that "the browser will figure which one it
needs anyway".

> remain robust against this kind of attack.

It's already the case by definition as long as the transmission operates
in clear. Anything can be put in the response, including some links or
whatever. If you have data showing that cookies are not passed anymore
cross redirects from HTTP to HTTPs, then that's fine and it means that
we don't need this anymore. But I never received complaints that haproxy
started to lose affinity on redirects, which makes me think it's still
valid.

> (`/.well-known/migrate-nonsecure-cookies`, for example)?

For many infrastructure components it's a pain because it involves
creating a storage *somewhere* that *someone* has to be in charge of,
and in mutualized environments it's a real pain.

> rather than minting a new header?

I really like this. It's by far the easiest solution. Usually nobody
cares about the load balancer's cookie name because the LB will remove
it before passing the request to the server, so this one can be changed
at will by the person responsible for the LB. There are always edge
cases of course, like a management page hosted on the application to
perform some specific tests or maintenance operations but the 1% doing
this know exactly what they're doing and will figure a different way
to do it.

> migration, which I think is valuable.

For the latter, just the LB, not the server, which is exactly what can
boost adoption.

> outside of a secure context.

The problem is that by breaking 10% of the web every 3 months we're
making everyone totally incompetent on infrastructure, rendering the
whole web totally insecure. I'd rather use motivation that trouble
making. Using the cookie name is perfect because it is visible in the
browser. So when your site requires that all your users see they learn
cookies called "insecure_something", you do have a great motivation to
try to improve the situation without being forced to rush an even more
horribly insecure hack to suit a browser's next imposed deadline that
threatens to destroy your site.

> 2.  HTTPS sites have persistent cookies.

That sounds reasonable to me as I said earlier.

> 3.  Never the twain shall meet.

Sorry, can't parse that :-/

> in that secure context.

Ideally yes, but ideally all the web would have been developed in 2019
and would be fresh new. The reality is that a lot of the content we use
was created way earlier by people having switched jobs and running on
components that are only maintained in good enough condition, and do
not evolve very quickly. By pressuring all content providers too much
we're progressively only keeping commercial stuff online and amateur/
enthousiast has no place anymore because of the hassle and costs
required by constant adaptations just to publish knowledge for free.
And I'm sensitive to remaining careful about this as well. So in practice
I'm also concerned about keeping the ability for a working site which
starts in HTTP with unimportant contents to decide to turn to HTTPS
when needed if that's the way the site works. It's always better to
do that than to make the situation so painful that they stay in clear
when that becomes quite borderline.

And that's still very frequent. A friend of mine who does a bit of
security consulting for small businesses told me that the hardest
thing he has to explain to customers is always to use HTTPS for
e-commerce sites! The risk of accidental breakage is often not
accepted. And that breaks because they're often left with too few
options to do what they need, which also means that once it works,
nobody's allowed to touch it anymore, so it's not even imaginable
to improve the situation from there! This is the reality of small
sites still using HTTP nowadays.

> I don't think we should add new attributes in order

I think that once the cost of switching the connection to HTTPS has been
digested, there's no point in going back to HTTP from HTTPS. However,
easing the transition from HTTP to HTTPS seems very important to
encourage migrating ealier in the session, even if reaching that
state requires several baby steps from the site's operator.

Cheers,
Willy

---

From: Mike West <[email-masked]>
Date: Sun, 15 Mar 2020 09:22:36 +0100

Hey folks,

I sketched out changes in a little more detail in an -01 of
https://tools.ietf.org/html/draft-west-cookie-incrementalism-01. That
sketch doesn't include either `__Nonsecure-` or `Sec-Nonsecure-Cookie`, as
I agree with Martin's suggestion that we should avoid them if possible. It
might be better for any such mitigation to live as a UA-specific workaround
rather than part of the core specification.

That said, I think I also agree with Willy's implicit claim that they will
be necessary for some period of time. The general experience we've had with
recent deprecations is that despite our best efforts, developers do not get
the message until we begin deploying a change. It seems quite reasonable to
me to plan for a multi-stage deprecation to minimize the potential for data
loss. That's almost certainly the path we'd try to take in Chromium. Other
user agents might be interested in being more aggressive.

Thanks again for the feedback! Willy, I'll pull out a few specific points
to respond to below:

> the other ones, considering that "the browser will figure which one it

I agree that this is likely, which is why I think it's important that any
stopgap is as short-lived as possible. The only way to ensure that
non-securely-set cookies can't influence the state of a secure site is for
the browser to stop sending them in any form. We should aim for that state
as quickly as practicable.

> started to lose affinity on redirects, which makes me think it's still

I agree that this kind of redirect works well in the status quo. This
proposal explicitly aims to break it in the future, as it seems bad for an
otherwise-secure site to be forced to trust data created over a non-secure
connection.

You're correct to say that there's little the browser can do to prevent a
non-secure site from sharing data with a secure site via other means (URL
parameters, server-to-server communication, etc). I don't think that kind
of one-off capability is a reasonable argument for baking that attack into
the state management mechanism that user agents offer as part of the
platform.

> this know exactly what they're doing and will figure a different way

For clarity: I did not intend for these cookies to stick around. I intended
this as a temporary carveout for applications to migrate their user data
from HTTP to HTTPS, not as something that would stick around in perpetuity.
Just as we don't allow `http://example.com/` to share `localStorage`,
databases, caches, etc with `https://example.com/`, I don't think there is
a good long-term solution for writing cookies in a non-secure context that
are trivially legible in a secure context.

> threatens to destroy your site.

We do need to come up with reasonable timelines for deployment if we agree
that this is the right direction in which to move. I am sympathetic to the
concern that we're dripping out changes over time, and it might well be
worthwhile to bundle up larger sets of changes so that developers can
respond to them at once.

> state requires several baby steps from the site's operator.

My intuition is that we're already pushing pretty hard on HTTP->HTTPS
migrations, and have built several tools over the past few years to help
both inside (`Upgrade-Insecure-Requests`, CSP reporting for `http:`
resources, "Not Secure" labels, etc) and outside (search console warnings,
various scanning/rating tools, etc) browsers.

At the same time, we really need to remove residual risk from non-secure
channels. The proposal in the document we're discussing seems to me a
reasonable compromise: non-secure channels are segregated from secure
channels, and only have access to temporary client-side state. This will
sincerely narrow the window of opportunity for network attackers, without
entirely breaking things like your printer's web interface.

I welcome feedback about the balance that compromise strikes. I'm certain
there are ways to tweak it that will have better results for all sides. I'm
reluctant to do so in ways that allow developers to continue pretending
that shipping non-secure sites is acceptable, but I think there's
substantial willingness to find solutions deployable in the short-term.

Thanks again for y'all's comments!

-mike