I've built a Single-Sign-On system for our web network. It works like this:
- User clicks a login link on the site he wants to log in to (the "Unsafe Site"). The unsafe site's ID is passed in the URL.
- He ends up on the system's (called "RAS") login page. This is on it's own domain, and may in the future get HTTPS, so the user can see his data is secure.
- The user logs in. A "session" is made on the server which holds the user ID, the unsafe site ID and an expiry time.
- The user's browser is redirected back to the unsafe site. The ID of the newly created session is passed as an URL parameter.
- The unsafe site sends a request for the user's data to RAS. It includes the session ID and some credentials which will identify and authenticate the unsafe site on RAS. (Note that the user and his browser are left completely out of this)
- The users's data (without the password) is returned to the unsafe site. The unsafe site then stores this in it's own session, or whatever, it doesn't matter.
(to see it in action, go to e.g. cncguild.net and click the login link near the top)
As you can see, this is pretty secure. At no point does the unsafe site have access to the user's password.
However, regarding usability, we'd like to better integrate the login process with the unsafe sites. The way to do this is to, instead of doing the whole "send to login page and redirect back", open up a popup of sorts. I currently see three possible method to do this:
Add an overlay div with the login form. Use AJAX to communicate with RAS until the login is complete and the client-side code receives the session ID. It can then handle the getting of the user data by sending this session ID to it's own server-side code (through a refresh or AJAX). While this would result in the best usability, there are some huge security pitfalls:
- The unsafe site's Javascript has access to the password
- While the user can check the source to see if it tries to steal it, who seriously does that?
Instead of putting the form in the same HTML document, let the overlay div contain an iframe with the login page.
- This hides the password from the unsafe site (if the browser has decent iframe Javascript security policies)
- There are no obvious browser interface markers to show the user that it's so. A malicious unsafe site author could therefore construct his own copy of the login form that looks exactly the same, but is not actually in an iframe.
- There is no way to communicate the session ID back to the unsafe site except for a refresh. No fancy AJAX logging in on the unsafe site possible.
Opening the login page in a real popup (window.open)
- URL and HTTPS icon are clearly displayed
- It can be real ugly. I'm not sure if the usability does actually benefit a lot relative to the way it works now.
What are your opinions on each of these three options? Of course, I expect ridicule of the first option. It rips the security to pieces. I've included it for completeness' sake. More options are also welcome
Re
If the user is sending a password to the RAS login page, it needs to use HTTPS unless all machines on that network are trusted.
Is the user ID cryptographically strong and sent via HTTPS? If not, then what stops one untrusted (unsafe?) site from guessing another site's user ID and requesting the data?
Re:
What stops this URL parameter from showing up in referrer headers sent to a third site if the user clicks on a link on the resulting page?
Re:
You're not going to be able to solve the trusted path problem in HTML no matter what you do. Setting up phishing domains is too easy. The only way to get trusted path is by using an authentication protocol that has it built in, e.g. HTTP AUTH. This post http://www.eros-os.org/pipermail/cap-talk/2009-February/012249.html talks about trusted path mechanisms for web applications.
Re:
There are many ways of communicating small amounts of data cross frame. Would one of the schemes listed on http://ajaxian.com/archives/crossframe-a-safe-communication-mechanism-across-documents-and-across-domains fit your needs?