Yevgeny Gorbachev | February 12th, 2020
Winter is coming… A cookie day for people and their agents – browsers, that may break your user experience or even affect your life… Will it be a global Armageddon of the Web, or just cause a local malfunction of some old-time sites? It’s time to figure it out.
Taste of HTTP Cookie
First of all, please welcome to the world of HTTP cookies. Mozilla Developer Network gives the following definition of cookie:
An HTTP cookie (web cookie, browser cookie) is a small piece of data that a server sends to the user’s web browser. The browser may store it and send it back with the next request to the same server.
It was intended to introduce the state of a web session for the stateless HTTP protocol. Cookies are set by a server and then sent back by the agent with every request to the server. That, in turn, allows to manage the session, personalize user’s preferences, or track user behavior.
Be Aware! Confidential information must never be stored in cookies, as the entire mechanism is totally insecure. The cookie values are visible to the end-user and can be changed by him or a man-in-the-middle. Cookies are often used to identify a user and their authenticated session, so stealing a cookie can lead to hijacking the session as well. Common ways to do that include Social Engineering or exploiting cross-site scripting (XSS) vulnerability in the application. That is why the proper baking of the cookies is so important.
Besides a data payload, the cookie may also have additional settings, instructing the user’s browser how to handle it. For instance, the cookie could be a session one that is deleted when the agent shuts down, or a permanent one, expiring at a specific date (Expires) or after a specific length of time (Max-Age).
All these instructions along with a cookie itself are specified by the server in the dedicated Set-Cookie header.
The Set-Cookie Header in a Nutshell
Set-Cookie: <cookie-name>=<value>[; <directive>[; <directive2>…]]
All the directives could be split in two major parts.
|<none>||A session cookie is erased when the client shuts down, and the session is over.|
|Expires||The maximum lifetime of the cookie in HTTP-date format.|
|Max-Age||A number of seconds until the cookie expires. A zero or negative number will expire the cookie immediately. If both Expires and Max-Age are set, Max-Age has precedence.|
|Domain||It defines the scope of the cookie: what hosts the cookies should be sent to.|
If omitted, it defaults to the host of the current document URL, not including subdomains.
If a domain is specified, subdomains are always included.
Note: A cookie for a domain that does not include the server that set it should be rejected by the user agent.
|Path||It defines the scope of the cookie: what URL path must exist in the requested URL in order to send the cookie.|
|Secure||A secure cookie is only sent to the server when a request is made with the https scheme. Insecure sites http can’t set cookies with the Secure directive anymore.|
|SameSite||Strict||The browser will only send cookies for same-site requests (requests originating from the site that set the cookie). If the request originated from a different URL than the URL of the current location, none of the cookies tagged with the Strict attribute will be included.|
|Lax||Same-site cookies are withheld on cross-site subrequests, such as calls to load images or frames, but will be sent when a user navigates to the URL from an external site; for example, by following a link.|
|None||The browser will send cookies with both cross-site requests and same-site requests.|
|In general, a cookie must not be sent with cross-origin requests (where the site is defined by the registrable domain), providing some protection against cross-site request forgery attacks (CSRF).|
Note: Browsers are migrating to have cookies default to SameSite=Lax. If a cookie is needed to be sent cross-origin, opt out of the SameSite restriction using the None directive. The None directive requires the Secure attribute.
|<prefixes>||__Secure||Cookies with names starting with __Secure-must be set with Secure flag from a secure page (TLS aka HTTPS).|
|__Host||Cookies with names starting with __Host-must be set with Secure flag, must be from a secure page (HTTPS), must not have a Domain attribute (and therefore aren’t sent to subdomains) and the path must be /.|
Now we are ready to dive into technical details about the upcoming changes in browser behavior. Google Chrome will be the first browser to roll out a change that might not be compatible with a web application. Here they are:
Since Chrome 80, cookies that do not specify a SameSite attribute will be treated as if they were SameSite=Lax with the additional behavior that they will still be included in POST requests to ease the transition for existing sites. Cookies that still need to be delivered in a cross-site context can explicitly request SameSite=None, and must also be marked Secure and delivered over HTTPS.
- Firefox already has these implemented with Firefox 69 behind a developer preference flag but has given no target release version for enabling it by default.
- Edge has announced support with an upcoming new version, but no ETA has been given on that yet.
- Safari has not signaled adoption yet.
- Others – No adoption signal yet.
Which Workflows May Be Affected
- Single sign on (SSO) integration with Identity Providers (idPs) via the protocols as SAML 2.0 and OpenID Connect/OAuth2.
When a web application implements SSO, several redirects happen under the hood for the user authentication from the agent to idP and back with authentication confirmation. That confirmation is represented by a token sent back to the app. The app performs the token validation for which it needs information stored in the session. Without any updates, the cookie carrying the session or authentication request binding info would no longer be attached to the POST response, resulting in the failure of the response validation checks and the inability of the end-user to sign in to the app.
- Embedding web application content from a third-party domain.
- Querying APIs from a third-party domain.
Why Is Google Pushing The Changes?
The short answer is: it brings more security. Previously, a vulnerability could cause an HTTP form to be submitted from the attacker’s context to the app that uses the attached POST request cookie to identify the end user’s session and execute a malicious action – for instance, a money transfer to the attacker. With the changes applied, the attack would not work because the POST is done from a different origin, the cookie will not be attached, and the action will fail. This change allows users to be protected by default but still allows applications to opt in for the less secure mode.
- February 4, 2020: Chrome 80 Stable released. The enablement of the SameSite-by-default and SameSite=None-requires-Secure enforcement will not be included in this initial rollout.
- February, 2020: Enforcement rollout for Chrome 80 Stable: The SameSite-by-default and SameSite=None-requires-Secure behaviors will begin rolling out to Chrome 80 Stable for an initial limited population starting the week of February 17, 2020, excluding the US President’s Day holiday on Monday. Google will be closely monitoring and evaluating ecosystem impact from this initial limited phase through gradually increasing rollouts.
That’s it. Now you know what’s going on, so handle this smoothly.
RFC 6265 HTTP State Management Mechanism, section 5.4: Cookie
MDN web docs. HTTP cookies
SameSite cookies explained
Upcoming Browser Behavior Changes: What Developers Need to Know
The Chromium project. SameSite Updates
Also, read new articles on our blog!