SO and SU just told me I've been logged in. I'm guessing because I'm already logged into my Google account... but how does SO know that?
I'm going to provide more than just the technical details here, as I think there are a lot of implicit assumptions about global login that aren't quite correct out there.
Accordingly, this is going to be really long.
- A user having logged into any SE-site will be automatically logged into every other SE-site on which they have an account
- Site level logins must not fail if the global login system is down
- Must not present unexpected sites or information to the user
- Must not degrade the anonymous user experience
1 is obvious, 2 is due to a strong desire not to introduce a new network wide dependency, 3 is shorthand for "don't scare off the user," and 4 is an acknowledgement of how much of our traffic is from anonymous users.
These are taken as axiomatic, any scheme that didn't fulfill all 4 was immediately discarded.
- Login as normal (unmodified code path)
- At the end, the user is given a global login token (attached as a cookie)
- The next page the user visits takes that token, and (via an IFrame) shovels it to StackAuth (stackauth.com)
- StackAuth verifies the token, and attaches a session key via localStorage
Visiting a New Site
- User hits any page on the site
- StackAuth checks localStorage for a session, and sends it to itself if it is.
- StackAuth validates the session, and (if valid) passes a login token to the SE-site via postMessage
- The SE-site validates the token, looks up the user, and (if valid, and the user is found) logs the user in
Some Technical Details
- Every step that passes data between the SE-site and StackAuth (I3, V2) uses a one-time-use request token to prevent XSRF attacks.
- All tokens are opaque to the user (more details below)
- The entire Visiting a New Site process is suppressed on a site after it is run once in a browser session.
- The idea is that once it has failed, the user is probably anonymous and it'd be a waste to keep trying. We allow users to force a login attempt by clicking "log in" to work around edge cases.
- This also implies that if you visit one site, then log in on another, and then go back to the first, you'll need to click "log in" to trigger the process.
- To see if your system meets all requirements, see the Network Login Troubleshooting page.
- Request Token Contains
- The requesting site
- The IP for which it is valid
- Login Token Contains
- The generating site
- The destination site
- The actual login credentials (roughly equivalent to the user's OpenId)
- We're using 256-bit AES in CBC mode (with PKCS7 padding) to encrypt all tokens
- Nonces are forced to be one-time-use
- Timestamps are also encoded in nonces, forcing tokens to expire
We're in a pretty novel position, as we cannot trust the user despite acting on their behalf. Conceptually, we have two of our sites (some StackExchange site, and StackAuth) communicating using the user's browser as the channel and as a data store. Accordingly, everything that passes through the user's browser (which is everything, really) must be cryptographically secure.
Acknowledging this, we turned paranoia up to 11 and went full on "defense in depth*." If anything looks "weird" we bail, and the user degrades to using manual logins.
Things We Check
- Your HTTP Referrer is one of our sites
- Your IP has been held constant between subsequent requests to the SE-site and StackAuth
- The sites encoded in the tokens are correct
- The tokens are no older than X minutes (its really tight, but subject to change)
- Nonces are never reused
Third-Party Cookies, SSL, and More
With some song and dance you can get Chrome, Firefox, and IE to accept third party cookies (most of the time anyway). Safari requires that you set these cookies via an IFrame, and convince the user to interact with it; which is quite possibly the suckiest user experience you can come up with for a global login scheme. A browser as popular as Safari just plain not working with any third-party cookie scheme just kills the entire technology for us.
There have been some SSL questions. The short of it: we don't use SSL anywhere in global login. SSL protects against man in the middle attacks between the user's browser and a website. As noted above, we don't trust the user so SSL doesn't actually solve any of our security problems. Also, currently our normal user session cookies (
usr on StackOverflow, for example) aren't sent over SSL; any attack against global login would work equally well once a user is logged in "normally". Naturally, if we switch to SSL across the sites we'll do the same in global login but right now it'd be pointless. SSL also imposes non-trivial performance penalties.
Inquiries have been made about open-sourcing our implementation of this scheme, or allowing third-parties to authenticate users with it. In short: no. This scheme makes very hard assumptions about how a site works, and thus isn't easily open source-able. For third-party authentication, I'd much rather use something more "standard" like OAuth2.0 (which isn't acceptable for us in network, since it assumes a many-to-one consumers-to-providers scheme).
*The idea is that an attacker has to jump through a lot of non-trivial hoops before they can even start to attack the actual cryptographic system.