44

I see iframe/p3p trick is the most popular one around, but I personally don't like it because javascript + hidden fields + frame really make it look like a hack job. I've also come across a master-slave approach using web service to communicate (http://www.15seconds.com/issue/971108.htm) and it seems better because it's transparent to the user and it's robust against different browsers.

Is there any better approaches, and what are the pros and cons of each?

Hedde van der Heide
  • 19,278
  • 13
  • 58
  • 93
Haoest
  • 12,718
  • 28
  • 86
  • 105

8 Answers8

63

My approach designates one domain as the 'central' domain and any others as 'satellite' domains.

When someone clicks a 'sign in' link (or presents a persistent login cookie), the sign in form ultimately sends its data to a URL that is on the central domain, along with a hidden form element saying which domain it came from (just for convenience, so the user is redirected back afterwards).

This page at the central domain then proceeds to set a session cookie (if the login went well) and redirect back to whatever domain the user logged in from, with a specially generated token in the URL which is unique for that session.

The page at the satellite URL then checks that token to see if it does correspond to a token that was generated for a session, and if so, it redirects to itself without the token, and sets a local cookie. Now that satellite domain has a session cookie as well. This redirect clears the token from the URL, so that it is unlikely that the user or any crawler will record the URL containing that token (although if they did, it shouldn't matter, the token can be a single-use token).

Now, the user has a session cookie at both the central domain and the satellite domain. But what if they visit another satellite? Well, normally, they would appear to the satellite as unauthenticated.

However, throughout my application, whenever a user is in a valid session, all links to pages on the other satellite domains have a ?s or &s appended to them. I reserve this 's' query string to mean "check with the central server because we reckon this user has a session". That is, no token or session id is shown on any HTML page, only the letter 's' which cannot identify someone.

A URL receiving such an 's' query tag will, if there is no valid session yet, do a redirect to the central domain saying "can you tell me who this is?" by putting something in the query string.

When the user arrives at the central server, if they are authenticated there the central server will simply receive their session cookie. It will then send the user back to the satellite with another single use token, which the satellite will treat just as a satellite would after logging in (see above). Ie, the satellite will now set up a session cookie on that domain, and redirect to itself to remove the token from the query string.

My solution works without script, or iframe support. It does require '?s' to be added to any cross-domain URLs where the user may not yet have a cookie at that URL. I did think of a way of getting around this: when the user first logs in, set up a chain of redirects around every single domain, setting a session cookie at each one. The only reason I haven't implemented this is that it would be complicated in that you would need to be able to have a set order that these redirects would happen in and when to stop, and would prevent you from expanding beyond 15 domains or so (too many more and you become dangerously close to the 'redirect limit' of many browsers and proxies).

Follow up note: this was written 11 years ago when the web was very different - for example, XMLhttprequest was not regarded as something you could depend on, much less across domains.

thomasrutter
  • 104,920
  • 24
  • 137
  • 160
  • 7
    This is very similar to oauth2. You have layered the automatic login on top of it, which is a good choice if you own all the apps. – matthuhiggins Aug 31 '11 at 23:09
  • Good answer, but I have just a few considerations over your answer: 1) You don't need to pass the satellite url as return, you can use the http header url-referer for this. 2) Your return token is unsafe, even if this is a single use token, an attacker can intercept the return postback and use the token outside the caller app before the validation completes, the right approach is generate a secure code on slave and validate the token with this code on central domain, the token is public but is useless to the attacker without the secure code. – Diego Mendes Sep 22 '15 at 00:40
  • 3) if you use a state-full server(user info stored on memory or DB), you don't need to change the url to check the login first, because the attacker may change the url on client side, the check must be made on every request, even without the query on url. So when a user request any secure url, you check if the user was authenticate(user info on memory) and if the authentication is still valid(after x hours of login) if not, you redirect him to the login server again. – Diego Mendes Sep 22 '15 at 00:40
  • [Here](http://stackoverflow.com/a/19546680/2218697) is post with image tag , is that a **better solution** ? – Shaiju T Dec 13 '16 at 09:33
2

That's a good solution if you have full-control of all the domains backend. In my situation I only have client (javascript/html) control on one, and full-control on another, therefore I need to use the iframe/p3p method, which sucks :(.

Luca Matteis
  • 28,287
  • 19
  • 109
  • 164
1

@thomasrutter

You could avoid having to manage all outbound links on satellites (via appending "s" to querystring) by making an ajax call to check the 'central' domain for auth status on page load. You could avoid redundant calls (on subsequent page loads) by making only one per session.

It would be arguably better to make the auth check request server-side prior to page load so that (a) you have more efficient access to session, and (b) you will know upon page render whether or not the user is logged in (and display content accordingly).

  • 1. We're talking about cross-domain, so AJAX is not an option by default 2. You cannot check on server without redirect, as you don't have anything to identify the user. – Marius Balčytis Sep 02 '15 at 16:02
1

The example in that article seems suspicious to me because you basically redirect to a url which, in turn, passes variables back to your domain in a querystring.

In the example, that would mean that a malicious user could simply navigate to http://slave.com/return.asp?Return=blah&UID=123" and be logged in on slave.com as user 123.

Am I missing something, or is it well-known that this technique is insecure and shouldn't be used for, well, things like that example suggests (passing user id's around, presumably to make one's identity portable).

Tom Lianza
  • 3,792
  • 4
  • 37
  • 49
  • Does anyone have an answer to this question? It seems like this would be important to know before apply the selected answer! – streetlight Apr 02 '13 at 12:11
  • No, because the master should send a unique token with the redirect that the satellite can validate. It should be noted, as with all mechanisms of http auth, that only https should be used. It is not very different from what oauth2 does. – ashwoods Sep 20 '13 at 13:45
1

Ok I seem to have found a solution, you can create a script tag that loads the src of the domain you want to set/get cookies on... only safari so far seems not to be able to SET cookies, but Ie6 and FF work fine... still if you only want to GET cookies, this is a very good approach.

Luca Matteis
  • 28,287
  • 19
  • 109
  • 164
  • Safari has a cookie acceptance preference default that only allows it to accept cookies the user has navigated to. Chrome and Safari share the same underlying engine (WebKit) but Chrome has this property set to "Accept All". Levels of default security arguements aside, this may be why Safar doesn't work in your arrangement. – ScottCher Apr 25 '11 at 13:25
0

We use cookie chaining, but it's not a good solution since it breaks when one of the domains doesn't work for the user (due to filtering / firewalls etc.). The newer techniques (including yours) only break when the "master" server that hands out the cookies / manages logins breaks.

Note that your return.asp can be abused to redirect to any site (see this for example).

mjy
  • 2,689
  • 1
  • 19
  • 22
0

You also should validate active session information against domains b,c,d,... this way you can only login if the user has already logged in at domain a.

-3

What you do is on the domain receiving the variables you check the referrer address as well so you can confirm the link was from your own domain and not someone simply typing the link into the address bar. This approach works well.

Mike
  • 1