What is difference between SameSite=Lax and SameSite=Strict in receiving cookies? - cookies

Some resources say that unlike SameSite=Strict, SameSite=Lax works when we load the other site using direct and top-level links... but as I tested, when I open a site from <a href="mysite.com">, browser treats it as typing mysite.com directly in address bar so it receives all cookies, even SameSite=Strict ones.
Same thing goes with <form action="mysite.com", method="get"> or <form ... method="post>", and the <form> request makes all cookies loaded completely.
So what's the difference between SameSite=Strict and SameSite=Lax?

Strict and Lax are about when your browser sends cookies. You tested when your browser receives cookies.
The browser uses the SameSite setting to decide when to send the cookie back to its origin.
Quoting from SameSite cookies explained:
If you set SameSite to Strict, your cookie will only be sent in a first-party context. In user terms, the cookie will only be sent if the site for the cookie matches the site currently shown in the browser's URL bar. So, if the promo_shown cookie is set as follows:
Set-Cookie: promo_shown=1; SameSite=Strict
When the user is on your site, then the cookie will be sent with the
request as expected. However when following a link into your site, say
from another site or via an email from a friend, on that initial
request the cookie will not be sent.
In contrast, SameSite=Lax allows the browser to send the cookie for the top-level navigations, such as described above: following a link on another site or clicking a link in an email.
Here is a summary on MDN, including the third value, SameSite=None:
The SameSite attribute accepts three values:
Lax
Cookies are allowed to be sent with top-level navigations and will be
sent along with GET request initiated by third party website. This is
the default value in modern browsers.
Strict
Cookies will only be sent in a first-party context and not be sent
along with requests initiated by third party websites.
None
Cookies will be sent in all contexts, i.e sending cross-origin is
allowed.
None used to be the default value, but recent browser versions made
Lax the default value to have reasonably robust defense against some
classes of cross-site request forgery (CSRF) attacks.
None requires the Secure attribute in latest browser versions.
If the HTML forms in your example are on another site, not mysite.com, cookies won't be sent back to mysite.com if they have SameSite=Strict. If SameSite=Lax, and the form has method="get", the browser will send the cookies, but with method="post", it will not.

Actually, when SameSite is set to Strict, cookies are sent when following a link in an Email, but only when the Email client is a standalone application, not browser-based. If you read your Email in a web app like gmail and click on a link, then it is a cross-domain request and is blocked by the browser.
When SameSite is Strict, cookies are sent when:
Following links from the same site
Entering the address directly into the address bar
Following a link from a non-browser application (Email client, Word document, ...)
When SameSite is set to Lax, it is sent in each of the above scenarios, plus
When you follow a top-level link from a different domain and it has a 'safe' method (GET, HEAD, OPTIONS). This is a link that changes the URL in the address bar, so a request in an IMG tag, IFRAME, etc, will not cause the cookie to be sent.

Related

Cookie blocked when attempt to be set during a 302 redirect within an iframe

I'm sure this is related to third party cookies, but I'm having trouble understand why this violates third party cookie rules.
I have 2 sites on different domains auth.example.com, app.someclient.com.
I'm using incognito mode in my browser with "Third party cookies" blocked (intentionally).
I have a page site.example.com where an iframe is shown and we load auth.example.com (note the same domains here *.example.com).
Users log in at auth.example.com within the iframe. Once we know they're a valid user, we redirect (302) the user to https://app.someclient.com/login_with_secret?secret=xy63ihfd209j... where secret is some short lived encrypted value to represent the user's identity.
When app.someclient.com receives the request, it decrypts the secret and sets a cookie on its side with the following settings:
Domain=app.someclient.com
Secure
SameSite=LAX
HttpOnly
As you can see, I'm not attempting to do something like set a cookie from the auth site or set the domain to be anything other than the domain that the request is being executed on (in this case app.someclient.com).
Why is setting a cookie as part of a redirect being blocked since the resulting cookie would be a first party cookie?

Cookie on same domain (First party) inside iframe not sending or saving

I have a SPA which uses a session token stored in a cookie for authentication with an API.
The SPA is on spa.domain.com, and the API is on api.domain.com; they share a common TLD.
The SPA sends a request CSRF token to the API, then sends a login request with the CSRF token and credentials to authenticate and create the cookie which is sent with subsequent requests.
This all works fine.
The problem I'm facing is that the SPA has an iframe, to which the src points back at a separate section of the SPA (The need for this is not the point of my question, i know it's convoluted but needs must).
The document loaded in the iframe has the same subdomain as the parent, i.e. spa.domain.com loads an iframe of spa.domain.com/iframecontents.
The page within the iframe skips cookies in Chrome and FF (Safari sends them an it works fine). I've looked at various threads about SameSite and Secure cookies and 3rd party vs first party but it is my understanding that this should simply be a first party cookie, i own the domains etc. (Although I have just realised locally the API is on one port and the SPA is on another port so that might account for different domains... just did a bit more reading, port is not included just the hostname)
It seems the cookies it already has for that domain are not being sent with the request
This cookie was blocked because it had the "SameSite=Lax"" attribute and the request was made from a different site and was not initiated by a top-level navigation.
and the cookies it receives to replace the ones the server thought were missing appear to be being ignored too
This attempt to set a cookie via a Set-Cookie header was blocked because it had the "SameSite=Lax" attribute but came from a cross-site response which was not the response to a top-level navigation.
The cookies look like this
path=/; domain=localhost; secure; httponly; samesite=lax
If I change samesite to none then it does work, but then I assume that means I'm just opening up my session cookies to being stolen by third parties in xss attacks? Seems nonsensical to me.
Why is an iframe on the same domain not working with lax and how might I work around this issue?

Does setting cookies 'SameSite=none; Secure' and providing CSRF-TOKEN suffice to prevent CSRF in embeddable web application?

My web application (myApp further) is embedded in iframe of a single third-party webpage. MyApp sets cookie Set-Cookie: JSESSIONID=38FE580EE7D8CACA581532DD37A19182; Path=/myapi; Secure; HttpOnly for maintaining users sessions. Sometime ago it stopped working in Chrome since https://blog.chromium.org/2020/02/samesite-cookie-changes-in-february.html update changed treating default behaviour for cookies without SameSite attribute from None to Lax.
I'm going to send cookies from myApp host with SameSite=None; Secure. Also X-CSRF-TOKEN header is included in every response. myApp javascript gets X-CSRF-TOKEN and puts it in header of every XHR request to myApp host. Does this suffice to prevent CSRF attack?
Should Access-Control-Allow-Origin: third-party-webpage header be added in responses?
I did more research and thought I would post my conclusion here.
I had misunderstood how the Antiforgery middleware worked.
The cookie configured by AddAntiforgery does not actually transmit the token to the client.
Instead it appears to be the encrypted or hashed token that is used to validate the token which must be provided in the header.
This allows the validation of the token to be done statelessly as the browser will pass the value of this cookie back with each request.
I refer to this cookie as the "validation cookie" below.
The middleware does not automatically transmit the token itself to the client.
That must be done by calling GetAndStoreTokens and providing the RequestToken value to the client to be set as a header for subsequent requests.
In our application we do that with a separate cookie (I call this the "token cookie" below).
Here's the Microsoft article demonstrating this technique.
I have determined that it is safe to use SameSite=None for the validation cookie and for the token cookie.
The SameSite setting does not have any effect on who can read the cookie value, it just determines whether or not the cookie will be sent to the server with future requests.
The validation cookie must be sent back to the server with future requests so that the token provided in the header can be validated.
It is acceptable that this cookie is sent even for cross origin requests since those requests will only validate if the token is provided in the header.
It is also acceptable for the token cookie to use SameSite=None since we are only using this cookie to provide the value to the client.
We never read this value from the cookie on the server when validating the token, the middleware reads the token from the header.
The value of the token cookie cannot be read by a different origin regardless of the SameSite property so that remains secure.
I also that realized that this exact pattern was employed by the Antiforgery middleware long before SameSite=Lax became the default value for cookies by chrome in 2020.
Prior to this the default behavior for the validation cookie would have always been None.
So I think it is reasonable to conclude that this technique is just as secure now with SameSite=None as it was before Lax became the default.
NOTE: There appear to be some browsers that don't handle SameSite=None correctly so the antiforgery process might fail for these browsers when the app is hosted in an iframe.

SameSite attribute in cookies

I have a website a.com that has third party app point to apps.b.com. When I login to a.com, I'm also authenticated to apps.b.com in the background using the same credentials. This is so the users do not have to login to access apps.b.com. I understand that browser sends all the cookies to apps.b.com when making the request to it. This is how it works now. Reading the article https://web.dev/samesite-cookies-explained/ in regards to SameSite attribute, it appears apps.b.com is third party site.
Now do I have to configure web server on a.com to set the cookie to SameSite=none;Secure OR do I have to set the SameSite=none;Secure on web server on apps.b.com?
Any time you are making a cross-site request that needs cookies, then those cookies need to be marked SameSite=None; Secure.
So, for example if the user is on a.com and you have an <iframe> or fetch() to apps.b.com that expects cookies, then the apps.b.com cookies need SameSite=None; Secure.
Vice versa, if the user is on apps.b.com and you are making requests to a.com to check their auth status by relying on the a.com cookies, then those cookies need SameSite=None; Secure.
Essentially the pattern you're looking for is when the site in the browser location bar is different to the site that needs the cookies, then those are the cookies that need marking. So, depending on your set up, it may be one or both.

CORS, withCredentials and third party cookies

I'm trying to do a CORS GET that sends the cookie along with it. I've set all the headers (access-control-allow-origin, access-control-allow-credentials, access-control-allow-headers) in the server and am using withCredentials: true and crossDomain: true in the jquery ajax request. Everything works when I tell my browser to allow third-party cookies. Is there any way to do this without forcing visitors to allow third party cookies? I've even tried redirecting the user and redirecting back, but CORS will refuse to send the cookie along. :/
I've tried doing the CORS request via ajax, as well as via an iframe.
I don't think it is possible. See my (old but relevant) blog post on this.
The only bullet-proof way is to use 1st-party cookies (that is, open window in a top-level window like a separate tab, or redirect current window).
In some cases it is not necessary though. Browsers have slightly different notions of what third-party cookie is, and default behavior is also different. This post has a nice overview on these details. So in some cases you could do tricks to enable (or at least detect) use of cookies on the page.
Other workarounds include putting one server under a subdomain of the other (subdomains are usually not considered 3rd-party), or changing the flow so that the user is authenticated by other means than cookies.
if you set cookie (origin 2 set cookie) you should know third party cookie will be used, but if you only get cookie (only send cookie for origin 2 without setting in response) there is no reason third party cookie play a role.
so i think you set a cookie in origin 2 and because of that force you enable third party cookie.
Note that cookies set in CORS responses are subject to normal
third-party cookie policies. In the example above, the page is loaded
from foo.example but the cookie on line 19 is sent by bar.other, and
would thus not be saved if the user's browser is configured to reject
all third-party cookies.
Cross-Origin Resource Sharing mozilla.org