Classic problem, a web app has secure and insecure pages (ie. account page is secure (HTTPS) and faq page is insecure (HTTP)), as a developer, I want the user to see a customized login button on the insecure pages (ie. it says 'click to login' if you are new to the site and 'Welcome User click to see your account' if you have a session.
To do this, I have secure cookies set by the server sent only when on the account page, but that account page (via jQuery) will also set an insecure cookie based on the secure one. The insecure cookies can be used by the browser to update the login button (via Javascript).
I am using a random string (randomized on the server each time) for the path to prevent the cookie from ever being sent over the wire. This data is just a username so it's not critical that it is completely locked down, however, it should still be guarded.
Cookie set here using jQuery (jQuery cookie plugin):
$.cookie('userLoggedIn', 'username', { domain: '.example.com', httpOnly: false, path: 'DFKLJGHDFDLFKHGAFDAKDJFH', expires: [one year], secure: false });
So far so good, but to a hacker, does path randomization work to prevent the stealing of insecure cookies?
I know that this is a very old question, but I will try to answer it.
Yes and No.
It doesn't necessarily need to be completely random - the only reason for it to be random is to make sure user never tries to get to that url, nor any ajax request goes there. To make sure that happens, you can use e.g. an UUID in the path.
You also need to make sure you control ALL of the JS on your domain.
That way the cookie will never get sent over the wire (the only way for it to get sent over the wire is for your JS to read it off document.cookie property and attach it or somehow send a request for that randomised URL).
A hacker won't be able to read the cookie, because browsers protect cookies from JS executed from other domains (protocol://domain:port combination has to match).
So the only way left to read off the cookie is to have access to the machine, then cookies can be read from disc as it is saved as plain text. But there are way more security vulnerabilities that come with having access to the user account.
So to answer your question, it is quite secure, but you have to keep in mind the vulnerabilities that come with such a solution.
Related
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.
What are the components of a browser,Which are the settings that control a browser, how cookies works ,how browser sessions work?
Huge topic here. Rather than break this down and write forever, I will go through a web scenario: User types in address (or clicks a link?) - NOTE: a bit oversimplified
Browser breaks down URI
Browser checks cache to see if site IP address is in cache
If no, browser contacts DNS server to get IP address
Browser creates request for resource at URI, which is a package that has both a header (for routing) and a body (the request). For a page address typed in or click, it will be a GET request. The browser also sends a collection of "capabilities" like I accept cookies, etc.
Server contacted and returns a response.
Browser breaks down the response. It may be a success or failure and there will be a return code either way.
Assuming success, the browser then parses the message and breaks it into the HTML for the page and any collections sent (for example cookies)
For cookies, the browser checks user preferences before storing. It should be noted there is more than one type of cookie today. There are user cookies, which contain user information and can be easily blocked by the user and server cookies, which contain information needed by the application server. The later can also be blocked, if desired, but it is generally not advised as you lose functionality.
The HTML is parsed so the page can be displayed (rendering engine) and all resources required to see the page (like pictures) are requested through a new web request and rendered on the page.
Components? You can derive some here. Request creator, response parser, page renderer, configuration (both standard and user), etc.
Settings? Too numerous to cover. Open a browser and look at settings to see quite a few.
Cookies? Covered the basics already.
Sessions? Handled by server cookies. If you restrict them you can only get one page at a time, unless some information is passed in the URI on each request.
When setting Cookiee on the server with properties(httpOnly and secure=true), does that mean it will only be secured during the communication beween server and client, but not after that?
In other words, if the value was originally in plainText -will it also be stored on the client side with plainText (after traveling with https ) -making it unsafe/vulnerable?
1) Do passwords needs to be always encrypt befors sending (even when using https)?
2) Where is httpCookiee (with secure=true) stored? and is this storage access is protected?
You probably don't want store the password.
What you need is store some "user is already authenticated" flag.
After all, you should learn about "digest access authentification". Storing hashed data is always plus.
This answer is too short, mainly bacause here is too much possibilities - and too much open questions.
Handling returning users:
You can manage (server side) an session database. in the cookie you storing only session ID. when the user authenticate itself, you're store into your server side database his status: "logged in". when he log out, you change in the DB status: "logged off".
Handling returning users has nothing with "storing passwords" in any way. You for example can authenticate users by external auth-services, like open-id, twitter, facebook etc., you're only storing his status by some session-ID or similar.
Browsers usually can store user-names/passwords, but this all time should be the user responsibility. When the user want only remeber his passwords, you should not store it in any way.
Why you want complicating your app and security mechanisms with storing encrypted passwords in cookies - what is not a correct solution - from any point of view?
Simple flow:
When an new user comes to your site - you assign him an new session-ID and store the SID into a cookie
when he login (via https) - you're store in your DB = "sessionID" -> "logged in"
when he return after a week, you can (server side) either accept his session-ID from the cookie - and from DB you can get his "logged-in" status, or, you can force login him once again (for example because of expiration)
all of the above is without any risk storing passwords in any way
1) I think so. Because even with secure flag, cookie will be stored in browser cache in plain text
2) It depends on browsers and OS. For Safari in Mac, you can find it in your ~/Library/Cookies/Cookies.plist You can see cookies with Secure flag but in plain text. It may be protected so only owner can see, but it never be good idea to have plain password anywhere in your computer
Once the secure flag is set to true, the cookie will be stored encrypted in the client even after the browser is closed. As you say it is unsafe/vulnerable.
Resp. 1)
Passwords can be encrypted before sending using Javascript, but it doesn't make much sense because https is doing the encryption for you.
Resp. 2)
The cookies are stored in the browser folder. Anybody can open the folder and see the cookies with a text editor.
The browser will handle the passwords for you. Just using a <input type="password"> and using SSL is secure enough.
And, avoid at all costs storing passwords in cookies.
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
I don't really understand when session is created and per what entity it is created (per ip, per browser, per logged in user). I see in documentation that sessions by default is created per visitor - but what is visitor (browser or ip)?
What are HTTP sessions?
To display a webpage your browser sends an HTTP request to the server, the server sends back an HTTP response. Each time you click a link on website a new HTTP transacation takes place, i.e. it is not a connection that is persistant over time (like a phone call). Your communication with a website consists of many monolitic HTTP transactions (tens or hundres of phonecalls, each phonecall being a few words).
So how can the server remember information about a user, for instance that a user is logged in (ip addresses are not reliable)? The first time you visit a website, the server creates a random string, and in the HTTP response it asks the browser to create a so called HTTP cookie with that value. A cookie is really just a name (of the cookie) and a value. If you go to a simple session-enabled Django site, the server will ask your browser to set a cookie named 'sessionid' with such a random generated value.
The subsequent times your browser will make HTTP requests to that domain, it will include the cookie in the HTTP request.
The server saves these session ids (for django the default is to save in the database) and it saves them together with so called session variables. So based on the session id sent along with an HTTP request it can dig out previously set session variables as well as modify or add session variables. If you delete your cookies (ctrl+shift+delete in Firefox), you will realize that no website remembers you anymore (Gmail, Facebook, Django sites, etc.) and you have to log in again. Most browsers will allow you to disable cookies in general or for specific sites (for privacy reasons) but this means that you can not log into those websites.
Per browser, per window, per tab, per ip?
It is not possible to log into different GMail accounts within the same browser, not even from different windows. But it is possible to log in to one account with Firefox and another with Chrome. So the answer is: per browser. However, it is not always that simple. You can use different profiles in Firefox, and each can keep different cookies and thus you can log into different accounts simultaneously. There are also Firefox plugins for keeping multiple sessions, e.g. MultiFox.
The session all depends on which session cookie your browser sends in it's HTTP request.
Play around
To get the full understanding of what is going on, I recommend installing the FireBug and FireCookie plugins for Firefox. The above screenshots are taken from FireBug's net panel. FireCookie will give you an overview of when and which cookies are set when you visit a site, and will let you regulate which cookies are allowed.
If there is a server side error, and you have DEBUG=True, then the Django error message will show you information about the HTTP request, including the cookies sent
It's browser (not IP). A session is basically data stored on your server that is identified by a session id sent as a cookie to the browser. The browser will send the cookie back containing the session id on all subsequent requests either until the browser is closed or the cookie expires (depending on the expires value that is sent with the cookie header, which you can control from Django with set_expiry).
The server can also expire sessions by basically ignoring the (unexpired) cookie that the browser sends and requiring a new session to be started.
There is a great description on how sessions work here.