Django session cookie: from (any) other domain, check if user is logged in - django

I have a domain domain1.com. The user logs in and a cookie is set. This is done using Django sessions.
I then go to another domain domain2.com. This domain runs javascript. From this javascript, I want to see if the user is logged into domain1.com.
Is this possible? Can I see a cookie belonging to domain1 from domain2? Or can I somehow via ajax make a call domain1 to check if the user is logged in?
Also, the user might originally have logged into domain1 from Chrome, but now they are accessing domain2 from another browser. Aren't cookies browser specific?
EDIT:
The real problem I am trying to solve? (re comment below): I have created a Chrome extension. When the user presses the extension icon from domain2, a javascript is run, which collects information from the page. This information needs to be sent to the user's account on domain1. Note that domain2 can be ANY domain, not one that I have created.
What I tried with AJAX and cookies.
set cookie from domain1:
response.set_cookie("user_cookie", value="somevalue", max_age=60*60, expires=None, path='/', domain=None, secure=None, httponly=False)
Create Python function, which is executed from domain1.com/checklogin:
#csrf_exempt
def is_logged_in(request):
cookie = request.COOKIES.get('user_cookie')
if cookie is not None:
return HttpResponse("1")
else:
return HttpResponse("0")
Go to domain1.com/checklogin -> The response is "1"
Call javascript from domain2 as follows:
var xmlHttp_1=new XMLHttpRequest();
xmlHttp_1.open("POST","http://domain1.com/checklogin/",false);
xmlHttp_1.send();
alert(xmlHttp_1.responseText);
The response here is, incorrectly, 0. It does not see the cookie created by domain1.
Note that domain1 is, at this point, localhost and domain2 is a real domain. Could this be the issue? It does properly call the function.

Is this possible? Can I see a cookie belonging to domain1 from
domain2?
No. Cookies are restricted to domains (and their subdomains). A cookie for .foo.com is accessible to www.foo.com, zoo.foo.com but not bar.com.
Or can I somehow via ajax make a call domain1 to check if the user is
logged in?
This is one way, yes and it will work.
Also, the user might originally have logged into domain1 from Chrome,
but now they are accessing domain2 from another browser. Aren't
cookies browser specific?
Yes, they are. If you are logged into Chrome, and you open Safari, you won't be logged in.

cookies are domain specific, you may share cookies between foo.example.com and bar.example.com but not between two domains. For work around, you need to send ajax request from domain two to domain one and check there if cookie as set and send response back to domain two.
Check this So question for reference:
Setting default cookie domain for Django site with multiple domain names

Related

Send Ajax request with cookie from 3rd Party Iframe - Safari 14+

I have a server side application that uses cookies for session management. The browser has some script that sends an ajax request to add information to the session. This is working well and in production.
The business wants to be able to insert this application in other companies' websites via iframes. ie myapp.com is in an iframe in otherbusiness.com and when the user clicks a button in the application in the iframe launched from myapp.com, it sends a request with a cookie that contains the session id to update the user's session on the myapp.com server.
For the browser to be able to send a cookie, 3rd party cookies needs to be enabled by setting the cookie options of SameSite=None and Secure. This works for all browsers except Safari.
Safari no longer accepts 3rd party cookies.
The only solution I can come up with is to use session ids in the URL but this is a little cumbersome.
Can anyone suggest a better option or perhaps a good implementation of session ids in the url?
I used hidden html fields to pass the session id and expiration.
My server side code checks for a cookie if it cannot find it, looks for the session id and expiration in the hidden fields.
This avoids security issues with passing the id in the url. It is a little clumsy to implement but it works.

Django Sessions: Correct way to get logged in user data from server?

I have my API set up using SessionAuthentication. Once a user logs in, I redirect them to their profile page in React. Once they are redirected to their profile page, I want to make a REST call to retrieve their profile data and insert it in the proper location on the page. I see a couple ways I can do this:
When a user logs in, put their User ID into the Response object (DRF) and then store that in the client somewhere (Redux store, session storage, or local storage). Then when they are redirected to the login page, make a REST call to /users/users_id.
With Django sessions the logged in user is automatically tied to each request. So do I even need to follow Rest here? I can make a call to /users, and if the user is authenticated, return their data.
I would appreciate any help with this. Thank you.
With SessionAuthentication, after a successful login, the browser saves a sessionId cookie for that domain (or ip:port) automatically. Sending a request will send that cookie from the same domain no matter with Django or React, and authenticate the user, making your request.user a user.
You can check for the cookie when you inspect the page -> Application -> Cookies -> Your domain -> sessionId
Basically, you can login via Django and it will login you with React as well. No need to store anything manually. Just use the same domain for both.

Secure django session cookies are overriden when a non-secure page is used

Setting SESSION_COOKIE_SECURE = True in Django tells the browser to only send the session cookie over SSL. However, if an authenticated user navigates from a secure page to a non-secure page the session middleware will not know about the secure session (since the cookie won't be sent) and will set a new session cookie. The effect is that the user is then logged out, and needs to log in again.
For example, a user might edit something in the secure admin, click "view on site", is taken to a non-ssl page, then clicks back, only to find that their session has been overwritten, and is no longer authenticated.
I'm just wondering what the preferred approach would be to solve this issue.
As I can see, there are the following solutions:
Use different (sub)domains for the secure / non-secure parts of the site. Force everything on the ssl domain to be ssl. (I know this would probably be the preferred option, but is currently not an option)
Use different django projects (and different session cookie names) for the secure / non-secure parts of the site. Use nginx to proxy to appropriate django project.
Create a custom middleware based on django.contrib.sessions.middleware.SessionMiddleware that manually handles sessions differently depending on secure / non-secure. Perhaps even check whether the url is an admin url, and use a different cookie name and cookie path.
Set SESSION_SAVE_EVERY_REQUEST = False and hope that the user doesn't navigate to pages that use cookies.

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

Django Sessions getting dropped when redirected from another domain

When a user visits my domain, a sessionid is issued by django. When he tries to do Oauth with Facebook, he clicks a button on my site which redirects to Facebook.com. Facebook redirects back to my domain, but at this point, the user's session is lost and Django seems to be issuing a new session variable.
I want the dropped session to persist because I must associate the visitor to my site with his Facebook account, but when the session is dropped, the logged in user is logged out.
I have a suspicion that this may be behavior related to django's XSS protection. How do I make the user information persist when the user leaves our site to log in at Facebook?
You might want to confirm that the cookies have the same domain when being created. That can sometimes cause problems. If you are going to the website www.example.com and the OAuth callback points to example.com, then it's possible you have two separate cookies, one for www.example.com and one for example.com
Turn on "Always Ask" on your browser and pay attention to the cookie details. Make sure that the value for the "Host:" field is the same both times.
The fix is entering something like .example.com for SESSION_COOKIE_DOMAIN in your settings.py file.
I've also just discovered that if you have two Django applications running on the same domain, to avoid cookie collision you may wish to set SESSION_COOKIE_NAME differently for each.