DEV Community

Cover image for SameSite Cookies and Why You Need Them
Teo Selenius
Teo Selenius

Posted on • Edited on • Originally published at appsecmonkey.com

SameSite Cookies and Why You Need Them

The original post can be found here.

What are SameSite cookies?

SameSite is a cookie security attribute introduced in 2016. Its purpose is to prevent cookies from getting included in cross-site requests in order to mitigate different client-side attacks such as CSRF, XS-Leaks and XSS.

What is a cross-site request?

It's a request from another website.

For example, when evil.com loads an image from example.com, it's a cross-site request. It's also a cross-site request when evil.com frames example.com or navigates to it.

So what's a site? To be specific, the site of an URL is calculated from the host part by taking the effective TLD (I'll get to the effective thing in a minute) and the part immediately before it. This combination is called eTLD+1.

So the host part of "https://www.appsecmonkey.com" is www.appsecmonkey.com.

And the effective TLD is com. And the part immediately before the TLD is appsecmonkey. So the site is appsecmonkey.com.

eTLD + 1

Using the same formula, the site for http://a.b.c.appsecmonkey.com:8080/ is also appsecmonkey.com.

eTLD + 1

Note that unlike cross-origin requests, the scheme (http) and port (8080) are not relevant in cross-site-requests.

Finally, I promised to clarify the effective TLD thing. The TLD of https://www.appsecmonkey.co.uk is .uk. But the effective TLD, or eTLD, is .co.uk. The list of these "eTLD suffixes" such as .co.uk is facilitated by the public suffix list.

eTLD + 1

To summarize, the site is eTLD+1, and any interaction where the source and destination have a different site is called cross-site.

Lax vs. Strict vs. None

SameSite cookies have three modes: Lax, Strict and None.

Generally, Lax is suitable for all applications, while Strict tends to be a better fit for security-critical applications. None is just for opting out.

Lax

SameSite=Lax will protect the cookie from cross-site interactions in a third-party context. These include:

  • evil.com loading a resource (image, style, script, etc.) from example.com.
  • evil.com loading example.com in an iframe.
  • evil.com submitting a form to example.com.
  • evil.com sending a fetch request to example.com.

Lax cookies, however, will be sent when navigating. For example:

  • evil.com has a link to example.com (which the user clicks).
  • evil.com redirects the user to example.com.
  • evil.com calls window.open('example.com').

You can use it like so.

Set-Cookie: foo=bar; SameSite=Lax; ...
Enter fullscreen mode Exit fullscreen mode

Strict

SameSite=Strict has all the protections of the lax mode, with the addition that it also protects the cookies when navigating.

Browsers include SameSite=Strict cookies only in first-party context, which is to say when the user types something into the URL bar and presses enter (or uses a bookmark).

While the strict mode is the most secure, it has drawbacks such as breaking links to the application, so it's not always suitable.

Set-Cookie: foo=bar; SameSite=Strict; ...
Enter fullscreen mode Exit fullscreen mode

None

SameSite=None opts out of the protection when you explicitly want to send the cookie in cross-site interactions. It is necessary because browsers have started to enable SameSite=Lax as the default (which is awesome).

In order to use SameSite=None, you are required to specify the Secure flag as well. The secure flag will prevent the cookie from leaking over an unencrypted connection. I don't fully understand the reasoning behind requiring it, but apparently, it has something to do with pervasive monitoring.

Set-Cookie: foo=bar; SameSite=None; Secure; ...
Enter fullscreen mode Exit fullscreen mode

At any rate, it's always a good practice to use the other cookie security features as well: Secure, HttpOnly and __Host-prefix.

Set-Cookie: __Host-foo=bar; SameSite=Lax; Secure; HttpOnly; Path=/
Enter fullscreen mode Exit fullscreen mode

SameSite vs. CSRF

One of the best features of SameSite cookies is their capability to prevent CSRF (Cross-Site Request Forgery) attacks.

Here is how a CSRF attack might work. Let's pretend that our user logs in to appsecmonkey.com, which sets the user's session cookie like so.

Set-Cookie: SessionID=ABC123; Secure; HttpOnly
Enter fullscreen mode Exit fullscreen mode

And a malicious website, evil.com, hosts the following HTML.

<form method="POST"  action="https://www.appsecmonkey.com/user/update-email/">
  <input type="hidden" name="new_email" value="attacker@evil.com" />
</form>
<script type="text/javascript">
  document.badform.submit();
</script>
Enter fullscreen mode Exit fullscreen mode

When the unwitting user browses to the URL, the following cross-site POST request to appsecmonkey.com gets sent from the user's browser:

POST /user/update-email/ HTTP/1.1
Host: www.appsecmonkey.com
Cookie: SessionId=ABC123
...

new_email=attacker@evil.com
Enter fullscreen mode Exit fullscreen mode

And the user's email address gets changed to attacker@evil.com.

However, if appsecmonkey.com sets the cookie as SameSite, and the same attack happens, the resulting POST request will not contain the cookie.

Set-Cookie: SessionID=ABC123; Secure; HttpOnly; SameSite=Lax
Enter fullscreen mode Exit fullscreen mode
POST /user/update-email/ HTTP/1.1
Host: www.appsecmonkey.com
...

new_email=attacker@evil.com
Enter fullscreen mode Exit fullscreen mode

And the user's email remains intact.

Note

CSRF synchronizer tokens are the primary defense against CSRF attacks. SameSite is merely an extra layer of security, hardening that should be used in addition to the actual security control (CSRF tokens) to achieve defense-in-depth.

SameSite vs. HTTP Verb Misuse CSRF

Imagine the same scenario, but this time appsecmonkey has blundered even worse than forgetting CSRF tokens. This time whe web application uses HTTP GET for changing stuff. Namely, the user's email address.

This means that just getting the target user to browse to the URL www.appsecmonkey.com/user/update-email?new_email=attacker@evil.com would be enough to change the email.

This time SameSite=Lax won't help. But if the web application sets the cookie in strict mode, the attack will fail again.

Set-Cookie: SessionID=ABC123; Secure; HttpOnly; SameSite=Strict
Enter fullscreen mode Exit fullscreen mode

SameSite vs. Reflected XSS

XSS (Cross-Site Scripting) vulnerabilities arise when untrusted data gets interpreted as code in a web context. They usually result from:

  1. Generating HTML unsafely (parameterizing without encoding correctly).
  2. Allowing users to edit HTML directly (WYSIWYG editors, for example).
  3. Allowing users to upload HTML/SVG files and serving those back unsafely.
  4. Using JavaScript unsafely (passing untrusted data into executable functions/properties).
  5. Using outdated and vulnerable JavaScript frameworks.

SameSite doesn't prevent all XSS attacks. But it can serve as a pretty good extra layer of security against reflected XSS, especially in Strict mode.

What are reflected XSS attacks?

XSS vulnerabilities are reflected if malicious links or websites can exploit them. For example, look at search.php here.

echo "<p>Search results for: " . $_GET('search') . "</p>"
Enter fullscreen mode Exit fullscreen mode

The URL parameter search gets reflected as part of the returned document's HTML structure. An attacker could create a link like so, rendering malicious JavaScript on the page when someone opens the link.

https://www.example.com/?search=<script>alert("XSS")</script>
Enter fullscreen mode Exit fullscreen mode

The returned HTML looks like this.

<p>Search results for: <script>alert("XSS")</script></p>
Enter fullscreen mode Exit fullscreen mode

How are XSS vulnerabilities exploited?

An attacker can exploit XSS vulnerabilities by injecting JavaScript code that performs unwanted actions in the logged-in user's session.

How does SameSite help?

In the above example, SameSite in Lax mode wouldn't help because it doesn't protect from navigating to links. If the XSS were in a POST request, then it would help.

However, SameSite in Strict mode would have prevented the attack.

SameSite vs. XS-Leaks

XS-Leaks (or Cross-Site Leaks) are a set of browser side-channel attacks. They enable malicious websites to infer data from the users of other web applications.

For example, browsers make it easy to time cross-domain requests.

var start = performance.now()

fetch('https://example.com', {
  mode: 'no-cors',
  credentials: 'include'
}).then(() => {
  var time = performance.now() - start;
  console.log("The request took %d ms.", time);
});
Enter fullscreen mode Exit fullscreen mode
The request took 129 ms.
Enter fullscreen mode Exit fullscreen mode

Cross-site timing makes it possible for a malicious website to differentiate between responses. Suppose that there is a search API for patients to find their records. If the patient has diabetes and searches for "diabetes", the server returns data.

GET /api/v1/records/search?query=diabetes

{"records": [{"id": 1, ...}]}
Enter fullscreen mode Exit fullscreen mode

And if the patient doesn't have diabetes, the API returns an empty JSON.

GET /api/v1/records/search?query=diabetes

{"records": []}
Enter fullscreen mode Exit fullscreen mode

Generally, the former request would take a longer time. An attacker could then create a malicious website that clocks requests to the "diabetes" URL and determines whether or not the user has diabetes.

You can expand the attack and search for a... b... c... d... yes. da.. db... di... yes. This sort of attack is known as XS-search.

How does SameSite help?

In this case, SameSite=Lax is enough to prevent the attack, because the fetch requests happen in a third party context. It also helps prevent other xs-leaks such as monitoring error events, frame counting, monitoring navigations and monitoring blur events.

Summary

Using SameSite cookies will significantly improve your application's client-side security, protecting against XSS, CSRF, and XS-Leak attacks.

The strict mode has drawbacks and might not be the best fit for most applications, but luckily the lax mode covers most attacks.

The lax mode is becoming the default as I write, so make sure you are ready for the change.

Get the web security checklist spreadsheet!

Subscribe
☝️ Subscribe to AppSec Monkey's email list, get our best content delivered straight to your inbox, and get our 2021 Web Application Security Checklist Spreadsheet for FREE as a welcome gift!

Don't stop here

If you like this article, check out the other application security guides we have on AppSec Monkey as well.

Thanks for reading.

Top comments (0)