Na navigaci | Klávesové zkratky

What are SameSite Cookies and Why Do We Need Them?

SameSite cookies provide a mechanism to recognize what led to the loading of a page. Whether it was through clicking a link on another website, submitting a form, loading inside an iframe, using JavaScript, etc.

Identifying how a page was loaded is crucial for security. The serious vulnerability known as Cross-Site Request Forgery (CSRF) has been with us for over twenty years, and SameSite cookies offer a systematic way to address it.

A CSRF attack involves an attacker luring a victim to a webpage that inconspicuously makes a request to a web application where the victim is logged in, and the application believes the request was made voluntarily by the victim. Thus, under the identity of the victim, some action is performed without the victim knowing. This could involve changing or deleting data, sending a message, etc. To prevent such attacks, applications need to distinguish whether the request came from a legitimate source, e.g., by submitting a form on the application itself, or from elsewhere. SameSite cookies can do this.

How does it work? Let’s say I have a website running on a domain, and I create three different cookies with attributes SameSite=Lax, SameSite=Strict, and SameSite=None. Name and value do not matter. The browser will store them.

  1. When I open any URL on my website by typing directly into the address bar or clicking on a bookmark, the browser sends all three cookies.
  2. When I access any URL on my website from a page from the same website, the browser sends all three cookies.
  3. When I access any URL on my website from a page from a different website, the browser sends only the cookies with None and in certain cases Lax, see table:
Code on another website   Sent cookies
Link <a href="…"> None + Lax
Form GET <form method="GET" action="…"> None + Lax
Form POST <form method="POST" action="…"> None
iframe <iframe src="…"> None
AJAX $.get('…'), fetch('…') None
Image <img src="…"> None
Prefetch <link rel="prefetch" href="…"> None
  None

SameSite cookies can distinguish only a few cases, but these are crucial for protecting against CSRF.

If, for example, there is a form or a link for deleting an item on my website's admin page and it was sent/clicked, the absence of a cookie created with the Strict attribute means it did not happen on my website but rather the request came from elsewhere, indicating a CSRF attack.

Create a cookie to detect a CSRF attack as a so-called session cookie without the Expires attribute, its validity is essentially infinite.

Domain vs Site

“On my website” is not the same as “on my domain,” it's not about the domain, but about the website (hence the name SameSite). Although the site often corresponds to the domain, for services like github.io, it corresponds to the subdomain. A request from doc.nette.org to files.nette.org is same-site, while a request from nette.github.io to tracy.github.io is already cross-site. Here it is nicely explained.

<iframe>

From the previous lines, it is clear that if a page from my website is loaded inside an <iframe> on another website, the browser does not send Strict or Lax cookies. But there's another important thing: if such a loaded page creates Strict or Lax cookies, the browser ignores them.

This creates a possibility to defend against fraudulent acquisition of cookies or Cookie Stuffing, where until now, systemic defense was also lacking. The trick is that the fraudster collects a commission for affiliate marketing, although the user was not brought to the merchant's website by a user-clicked link. Instead, an invisible <iframe> with the same link is inserted into the page, marking all visitors.

Cookies without the SameSite Attribute

Cookies without the SameSite attribute were always sent during both same-site and cross-site requests. Just like SameSite=None. However, in the near future, browsers will start treating the SameSite=Lax flag as the default, so cookies without an attribute will be considered Lax. This is quite an unusually large BC break in browser behavior. If you want the cookie to continue to behave the same and be transmitted during any cross-site request, you need to set it to SameSite=None. (Unless you develop embedded widgets, etc., you probably won't want this often.) Unfortunately, for last year's browsers, the None value is unexpected. Safari 12 interprets it as Strict, thus creating a tricky problem on older iOS and macOS.

And note: None works only when set with the Secure attribute.

What to Do in Case of an Attack?

Run away! The basic rule of self-defense, both in real life and on the web. A huge mistake made by many frameworks is that upon detecting a CSRF attack, they display the form again and write something like “The CSRF token is invalid. Please try to submit the form again”. By resubmitting the form, the attack is completed. Such protection lacks sense when you actually invite the user to bypass it.

Until recently, Chrome did that during a cross-site request—it displayed the page again after a refresh, but this time sent the cookies with the Strict attribute. So, the refresh eliminated the CSRF protection based on SameSite cookies. Fortunately, it no longer does this today, but it's possible that other or older browsers still do. A user can also “refresh” the page by clicking on the address bar + enter, which is considered a direct URL entry (point 1), and all cookies are sent.

Thus, the best response to detecting CSRF is to redirect with a 302 HTTP code elsewhere, perhaps to the homepage. This rids you of dangerous POST data, and the problematic URL isn't saved to history.

Incompatibilities

SameSite hasn't worked nearly as well as it should have for a long time, mainly due to browser bugs and deficiencies in the specification, which, for example, didn't address redirections or refreshes. SameSite cookies weren't transferred during saving or printing a page, but were transferred after a refresh when they shouldn't have been, etc. Fortunately, the situation is better today. I believe that the only serious shortcomings in current browser versions persist, as mentioned above for Safari.

Addendum: Besides SameSite, the origin of a request can very recently be distinguished also by the Origin header, which is more privacy-respecting and more accurate than the Referer header.

4 years ago in section PHP | blog written by David Grudl | back to top

You might be interested in


phpFashion © 2004, 2024 David Grudl | o blogu

Ukázky zdrojových kódů smíte používat s uvedením autora a URL tohoto webu bez dalších omezení.