SameSite attribute, as defined in RFC draft RFC6265bis, was introduced to improve browsers’ built-in protection against CSRF attacks by not including the cookies in certain cross-site requests, depending on the value of the attribute.
Site is defined as a combination of scheme (i.e. http or https) and TLD+1 domain name. So https://so.many.subdomains.example.com and https://www.example.com and are same site (though not same origin).
How do SameSite cookies work?
There are 4 options that exist when cookies are set by a web site:
- SameSite attribute is specified, there are 3 different values that can be used — None, Lax, and Strict.
- No SameSite attribute is specified, these cookies are treated as SameSite=Lax. In Chrome, a cookie with no SameSite attribute that is at most 2 minutes old will still be sent on a top-level cross-site POST request (documentation, this seems to be temporary behaviour).
When a cookie is set as SameSite=Strict, it is never included in cross-site requests (i.e. if the target site for the request doesn’t match the the site for the page shown in the address bar). Note, that this might break deep links into applications (when cookies are used for session management) — consider a user clicking on such link in a webmail client, the application will not receive the cookies and will display an error or prompt for authentication.
When a cookie is set as SameSite=Lax, it will be included in “safe” cross-site requests only. Specifically when the request uses the GET method AND the request resulted from a top-level navigation by the user, such as clicking on a link. The cookie is not included in cross-site POST requests, or cross-site requests initiated by scripts on the page.
When cookie is set as SameSite=None, it will effectively disable all the SameSite protections and the cookie will be sent in all contexts. In this case, Secure attribute should also be specified for the cookie.
When is SameSite not effective?
2 minute rule in Chrome
When no SameSite attribute is not present on a cookie, Chrome will not apply Lax restrictions for 2 minutes after the cookie is set. I believe this was a workaround for some single sign-on solutions being broken after the introduction of SameSite attribute and is supposed to be temporary. This technique can be combined with a forced cookie refresh.
When an application performs mutating actions when handling GET requests and uses SameSite=Lax setting on the cookies. Lax option doesn’t affect handling of cookie in GET requests and hence doesn’t protect against CSRF in this scenario.
Vulnerable sibling domains
If a sibling domain can be compromised through XSS, or allows hosting attacker-controlled content, it is possible to bypass SameSite restriction by making same site requests (even through they will be cross origin). So an application hosted on https://megavault.com can be affected by https://no-so-secure.and-very-obscure.megavault.com. This works for all SameSite settings, including Secure.
If an application contains client-side redirects, they might be used to route CSRF attacks through the redirect in a way that makes the request same site and bypass SameSite protections. This works for all SameSite settings.
When using cookies, one needs to be mindful of CSRF. SameSite is good as defense in depth, but doesn’t prevent all possible CSRF attacks. There are a number of scenarios where a CSRF attack can be successful even when SameSite attribute is set on cookies, including mutating GET requests and vulnerabilities in sibling domains.
For comprehensive guidance on protecting web applications against CSRF attacks, check OWASP’s CSRF Prevention Checklist (link below under References). Effective approaches include synchronizer token pattern, double submit cookies, custom request headers and not using cookies for session management.
Bypassing SameSite cookie restrictions (PortSwigger Academy)