Saturday, June 02, 2007

Building Secure Single Sign On Systems and Google

After seeing several posts which spelled doom and gloom if there was ever found an XSS hole in any of Google's because they used a Single Sign On (SSO) System I started trying to think of a method in which secure sign on could be securely implemented, where all the SSO server side code is trusted, e.g. when you own all the websites, and here's what I came up with.

Idea 1: Remote Javascript



The first thing that came into my head was using Remote Javascript files, to give any SSO site (site specific of course), which the server side back-end could then use to query a database, to check that the specific token was valid for their site, and if it was, they would be issued another site specific login token, which would be placed in a user's cookie, and session management would resume as usual.

The problem with this is, of course, making sure that no other sites can retrieve this login token by including the same remote javascript in their page.

Of course, there are several things you could do to prevent this:

You could do referer checks. While we have seen methods to spoof or strip referers, there have been no methods to my knowledge to date which can do this when you're requesting script elements. You could technically spoof the header normally, and try to poison the cache, but as long as the appropriate cache headers are sent, then this should not be possible.

But this leaves any users who have referer stripping firewalls in danger, and this is unacceptable.

You could use CSRF style protections. But this faces the problem of what you can actually tie the token to. You could tie the token to the IP, but as long as Anti-DNS Pinning works, this can be attacked and broken, so this is not a valid solution. And Furthermore doing such checks would be rather expensive in terms of operations needing to be performed, since this is being done between separate servers/sites.

Which essentially means that while we can make this system secure for most people, there are some we would not secure, and it is therefore not viable.

Idea 2: Remote iframes


I kept thinking about other ways you could send data to a specific site only and (from my attempts to break SessionSafe) I remembered that we could use iframes.

If an iframe sets the window.top.location.href property, the page which loaded the iframe cannot read that value, and even if they could it would be considered a browser bug and fixed. So to transfer data to our domain and our domain only we would do the following:

Write an iframe to the page which looked like this:
<iframe width="300" height="150" src="http://ssodomain.com/login.php?site=Service"></iframe>

And on http://ssodomain.com/login.php the following would be done:

If the user is not logged in display a login form.

If the user is logged in then write the following javasript tot he page:

window.top.location = 'http://companyownedwebsite.com/verify.php?auth=123456';

Where companyownedwebsite.com was determined by a switch statement on the site variable, so that only a valid site could be redirected to, and so the SSO service knew which particular value to parse in auth variable.

The other mechanisms are the same as in Idea 1. Furthermore this protects you from Programmatic password theft, since the password is entered on a domain which has nothing other than a login form.

Google's Approach


After thinking of Idea 2, I realised that this is what google does; on most of their services anyway. The one service (at which I initially looked to find out how Google implemented SSO, *doh*) which doesn't use the exact same method as above is Gmail. What it turns out Gmail does (which I somehow missed) is, instead of using an iframes, they redirect gmail.com to the equivalent of http://ssodomain.com/login.php?site=Gmail where the whole login page is displayed, and the form is submitted to that same domain.

So what does this mean?



I came to the same idea independently of Google (which to me says that there must be some merit to it, sine I didn't just see the idea and say; hey, this looks good), and it should in theory and practice be perfectly sound as long as a website cannot tell determine the URL to which the iframe/a page loaded in an iframe is being redirected to, and there are no XSS holes in the SSO domain.

So Google's SSO should be secure in the face of an XSS hole?



Well, no; Google messed up; they made their SSO domain www.google.com; the same domain as their main site, which means it used used for more central purposes (central in terms of design, rather than importance). This is bad, because there should be nothing on the SSO domain other than SSO forms, because otherwise one may find XSS holes in the SSO domain, and that breaks the whole system (bar things like IP locks tying the sessions together, but with Anti-DNS Pinning, this can again be broken)

So what are you trying to say



What I'm trying to say is that all XSS holes which are not in www.google.com (and yes, the www is important) will not break SSO, but any XSS hole which is in that domain, has the potential to.

Oh, and Google isn't completely hopeless when it comes to security - they just have many more developers working for them, and many more web facing projects than most organisations.

No comments: