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

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?

Related

How to make login cookie from one subdomain work with another

I have a web server, written in C#, which allows login, and records a session cookie to allow access subsequently.
This code servers two domains a.example.com and b.example.com.
When the user opens their browser and logs on to a.example.com, the server sets two cookies (these taken from the response header received in the browser):
session=DLFNFYFGPXEGWOPAJYRT; Max-Age=3599, session=DLFNFYFGPXEGWOPAJYRT; Domain=.example.com; Max-Age=3599; Path=/
If the user then connects to b.example.com, I would expect the Request header from the browser to contain the second cookie above. It doesn't - it contains no cookies at all.
Am I misunderstanding how cross domain cookies work?

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?

What is difference between SameSite=Lax and SameSite=Strict in receiving 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.

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.

Automatic cookie single sign on on multiple domains - like google

I don't understand how google achieve the following mechanism of single sign on:
I login in gmail for example (I suppose this creates a cookie withmy authorization)
I open a new tab and direct type the url of "youtube"
Then I enter youtube logged in.
How can this second site detect that I've already been logged in.
They are different domains. Youtube can't read the cookie of Gmail.
All the solutions I've read about Single sign on don't allow this. The client always ask permission to a central login app.
In my example YouTube doesn't know I am the same user logged in Gmail (actually it does know, but I don't understand how)
Note that I type the url of "youtube" by hand. I don't clic the youtube icon from the upper toolbar of gmail (In that case gmail may pass some auth params through the url for example).
The cookies are set on specific domains. Ex:
setcookie(name,value,expire,path,domain)
When you log in on gmail, before "mail.google.com", you have been redirected to "accounts.google.com" then to "mail.google.com" so the cookies are on "accounts.google.com" too.
In this case, the domain is "accounts.google.com" and the path is "/" (the home path).
When you request "www.youtube.com" then you click on "connection" it requests
"accounts.google.com" fast so you can't see this redirection and checks if you have cookies on "accounts.google.com". If so, it checks if the cookies are valid and not expired, or user not banned... Then it redirects you to "www.youtube.com/signin?loginthisSession=Sessionid". This request contains the value of the of sessionid cookie catched from the cookies of "accounts.google.com".
In the last step, "www.youtube.com" logs you and set its own cookie on the domain "www.youtube.com" and saves them.
So the trick is on the 302 HTTP redirect.
Update
i do not know why people keep mentioning iframe take a look at the date whene this questions was posted on 2016 google was not using then iframe as i mentioned the capture of web traffic as you can see SetSID wich means set the cookie of SESSION_ID from accounts.google.dz(com) then redirects to youtube.com it can not be used trought iframe differant domains security measure you can not be redirected from domain to domain trought iframe neither please read this before posting
Cookies and localStorage can be shared between domains using an intermediate domain. On the home page is embedded an "iframe ', which accesses cookies and sends messages to the main.
mail.google.com and youtube.com can share the cookies using accounts.google.es. Open Chrome->Inspect->Resources->Local storage and you will see in accounts.google.com the authentication token in JWT format.
I have detailed the technical steps in this answer: https://stackoverflow.com/a/37565692/6371459. Also take a look at https://github.com/Aralink/ssojwt to see an implementation of a Single Sign On using JWT in a central domain
Check this out.. http://www.codeproject.com/Articles/106439/Single-Sign-On-SSO-for-cross-domain-ASP-NET-applic.
The article consist explanation and sample of SSO cross domain.
As far as I remember, if I am not wrong, cookies contains a specified field that contains the domain that can read and get such cookie. That is made in order to prevent certain web sites to read all your cookie list and make your own business. You should be able to see which kind of sites can 'see' your gmail cookie.
Correct me if I am wrong, this should compile the answer given regarding the SID and gmail-YouTube example..
While evaluating this cross domain SSO topic, I have come up with possible a new SSO synchronization flow using cookie with timestamp. Although it is not a flow used by Google, I think this flow is possible to implement for system with limited number of domains.
This flow do not use 3rd party cookie
This is going to be a long post :)
domains
To make an example, let say we have these domains for our example pet forums:
https://account.domain1.com (For SSO Login)
.domain1.com (e.g. https://cat.domain1.com)
.domain2.com (e.g. https://dog.domain2.com)
.domain3.com (e.g. https://rabbit.domain3.com)
Change to https://account.domain1.com:
Add https://account.domain2.com and https://account.domain3.com, route both host name traffic to the server hosting https://account.domain1.com
Login Steps:
User go to dog.domain2.com, user have not sign in yet.
User click the Login button in dog.domain2.com
User get redirect to account.domain1.com for login
This step can be any Login protocol, OAuth, OIDC, SAML, CAS, etc
So, it is important for user to be redirected back to original page after login
Let say this https://account.domain1.com?redirect_uri=https://dog.domain2.com
redirect_uri as in the URL to go back after login success
User Input username & password, login success
New step, before redirect back to https://dog.domain2.com, set cookies on all domains
Redirect browser to https://accounts.domain2.com?...
Set a cookie on the .domains2.com domain (More on the cookie value later)
Redirect browser to https://accounts.domain2.com?...
Set a cookie on the .domains3.com domain
Redirect browser to https://accounts.domain1.com?...
Set a cookie on the .domains1.com domain
Redirect back to original flow
Redirect user back to their original service, i.e. https://dog.domain2.com
Now, right after login flow we have cookies over all 3 domains. Any of our service (e.g. https://cat.domain1.com / https://dog.domain2.com / https://rabbit.domain2.com ) can access this cookie under their own domain.
Cookie Content
The content of the cookie, should allows for any webpage to look at it, and determine if SSO sync is needed
Different types of cookie content can be stored, including
Boolean indicate user logined or not
User ID
Expired At timestamp
Boolean indicate user logined or not
Storing have_user_login = true / false have sync issue
Suppose User A login, visit https://cat.domain1.com, User A Logout, and User B login
Now, from https://cat.domain1.com standpoint, no sync is needed
However, https://cat.domain1.com is storing User A instead of User B, hence the sync issue.
User ID
While it is tempting to just stored the user_id on those cookie, and let all the domain to see them and set the user accordingly.
This is way too dangerous, since the cookie is set at the parent domain,
if any of the website under your domain been hacked, impersonation might happen (Copying any of the user_id, pasting it to their own browser cookie).
Expired At Timestamp
What I suggest, is for the cookie value to set as the SSO expired time, and set the type as session cookie, this have the following benefits:
An expired time have minimal security impact if leaked / altered
Our website can check the expired time to know if user need to relogin
As for why session cookie, is for when user close them browser, and tried to login again, the cookie will be deleted hence logout the user as well
Any webpage that use the SSO, should also stored a cookie themselves with the same expired time
There will be cases that, User A Login, visit https://cat.domains1.com Then User B Login
Since User A and User B will have a different login expired time, storing and compare that timestamp will tell the user to sync with SSO again
Example checking implement for your service
E.g. On https://cat.domains1.com, you can add this to the top of your page load
<?php
$sso_expired_time = $_COOKIE["sso_expired_time "] ?? 0;
$website_expired_time = $_COOKIE["website_expired_time "] ?? 0;
if( (int) $sso_expired_time < time() || $sso_expired_time !== $website_expired_time ) {
// User not sync, perform sync
setcookie("website_expired_time", $website_expired_time,0,"/", $_SERVER['SERVER_NAME'], true, true);
// Redirect to https://account.domain1.com for Login
// Or, Initiate the login sequence for your selected login protocol
header("Location: https://account.domain1.com/.....")
exit;
}
// User is sync
// Page load success, continue other operation
Logout
Login is very similar to Login, basically:
Before logout goes through, redirect to all 3 domains just like login
Remove the SSO cookie
Continue the normal logout flow
Pro and cons for the methods:
Pro: All domain sync possible
Pro: No need to relies on 3rd party cookie
Cons: First time login longer (around 50ms longer)
Cons: Customization on every website is needed for the sync to works