I have been working on a Authentication and authorization module similar to how stackexchange is in place. Now I am sure they use a certain model of oAuth or a token generation server that authorizes uses to their various sites. I tried a little experiment.
Once I am logged into Stackoverflow, I delete all my cookies from the developer console.
I leave my localstorage object intact which contains a key se:fkey xxxxxxxxxxxxxxxxxxxxxxxxx
for stackoverflow domain.
there is another key for stackauth domain GlobalLogin: xxxxxxxxxxxxxxxxxxxxxxx
the se.fkey if I used for a session hijack, nothing happened. but the GlobalLogin, I was able to copy and hijack my session. So, my query would be, how does S/O deal with the authorization post authentication for each one of the sites. Also, is there a way to invalidate the globalLogin for them after it is used once?
{EDIT1}
So, just the globalLogin
alone is enough. If you can get that key, just open a private browsing instance. In the Localstorage for stackauth when you are in the login page, create the key-value
mapping and refresh the page. You will be logged in.
{EDIT2}
The globalLogin
key seems to be consistent across multiple sessions. It has been a day and no refresh of my globalLogin
key. Safe to assume if you key is hijacked, the attacker will have access to your profile indefinitely.
{EDIT3}
For everyone who is voting and will vote for this question as not a programming related question. Let me put it this way, how do we store SSO's on the web browser with localstorage safely and since they are prone to get compromised, what do we need to do prevent it from happening? One of my colleagues was considerate enough to give me his GlobalLogin key, I was able to hijack his session from a different computer albeit it was on the same network.
PS: This is purely for theoretical understanding that I did this.
On the downside, localStorage is potentially vulnerable to cross-site scripting (XSS) attacks. If an attacker can inject malicious JavaScript into a webpage, they can steal an access token in localStorage. Also, unlike cookies, localStorage doesn't provide secure attributes that you can set to block attacks.
If you store it inside localStorage, it's accessible by any script inside your page. This is as bad as it sounds; an XSS attack could give an external attacker access to the token. To reiterate, whatever you do, don't store a JWT in local storage (or session storage).
A JWT needs to be stored in a safe place inside the user's browser. Any way,you shouldn't store a JWT in local storage (or session storage). If you store it in a LocalStorage/SessionStorage then it can be easily grabbed by an XSS attack.
Well, rather than looking at the vulnerability, let's look at the possible attack vectors. I'll add a table here as a TL/DR
Attacker | Vulnerable? Eavesdropper | Yes MITM | Yes Local Attack | Yes Server Attack | Yes
So yes, it is an issue.
Consider this a passive attacker in a coffee shop. They can see all of the TCP level traffic.
The requests back and forth to SO are -by-default- not encrypted. You can browse via HTTPS, but by default it's HTTP only.
So an attacker can see any request go by, and inspect/steal the data.
So let's see if the GlobalLogin
token is ever sent in a request...
As a matter of fact, it is. On the login page, a request is sent via an iframe to the following URL:
https://stackauth.com/auth/global/read?request=//snip//
That URL returns a script:
var data = { "ReadSession":"https://stackauth.com/auth/global/read-session", "Request":"//snip//", "Nonce":"//snip//", "Referrer":"//snip//", "StorageName":"GlobalLogin" }; var toMsg = window.parent; var obj = localStorage.getItem(data.StorageName); if(obj != null) { var req = new XMLHttpRequest(); req.open( 'POST', data.ReadSession+ 'request='+encodeURIComponent(data.Request)+ '&nonce='+encodeURIComponent(data.Nonce)+ '&seriesAndToken='+encodeURIComponent(obj), false ); req.send(null); if(req.status == 200){ toMsg.postMessage(req.responseText, data.Referrer); }else{ toMsg.postMessage('No Session', data.Referrer); } }else{ toMsg.postMessage('No Local Storage', data.Referrer); }
Now, notice that the GlobalLogin
is sent over HTTPS to the server. So a remote attacker, who can read traffic will not be able to get the GlobalLogin
token.
So the GlobalLogin
portion is safe from eavesdroppers.
However, note that it's still quite vulnerable to sniffing the session cookie, since it's sent over HTTP.
Well, here's where things get interesting.
If you can modify traffic, you can do something really fun.
The initial page creates an iframe bringing in the above stackauth.com URL via HTTPS. Well, if you can modify the initial page (also possible via XSS), you can downgrade the request to HTTP.
And StackAuth.com will be just fine with that. When it makes the request to stackauth.com, you would need to intercept that as well, and change its ReadSession
URL to be HTTP as well.
But then, all you need to do is watch the call to the ReadSession
URL, and boom, you've stolen the GlobalLogin
token.
But the traffic is HTTP anyway, so it doesn't matter since you don't need to go through that trouble to steal the cookie. So why bother?
If the person has access to the computer to read the local storage file, they can do FAR worse than just steal your login token.
There's a class of attack called "Browser In The Middle", where a compromise in the browser allows an attacker to do whatever they want.
And there's no real effective protection against it other than to try to keep the browser secure (there's nothing you can do from your end).
So if an attacker can get local access to the computer, it's game over.
If an attacker can get access to StackOverflow's servers, it's game over anyway...
As long as HTTP is allowed (since a MITM can always downgrade the connection to HTTP), there's nothing to protect as session secrets always be stealable via eavesdropping.
The only way of protecting this information is to use HSTS and force HTTPS everywhere.
It's worth noting that you could protect GlobalLogin
by forcing HSTS on stackauth.com, leaving the main site accessible over HTTP. This wouldn't prevent the effect of the attack (session hijacking). But it would protect the one vector.
But going HTTPS only via HSTS everywhere would be the best and really only way to prevent these kinds of problems. Anything else would be a bandaid on a gunshot wound.
Note: I did talk to SO about this prior to posting this.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With