Login Information Leak: How to prevent it?

Recently it became well-known that websites can leak information about a user based on if that user is logged in or not with this example that can demonstrate the issue. I’d recommend reading that page for a quick overview of how it can be done (but note that it is not the only way, as I will discuss below). So how can we properly prevent this information leak?

As you probably learned from the above link, the ability to trigger an automatic redirect to an image (or video, audio, etc.) based on login can be used to determine if a user is logged in on that site. You might say: No problem! I just won’t allow redirects to non-HTML content! Problem solved! Right?

Wrong! While that may stop this specific technique, it won’t stop other tricks. For example, recently I discovered and demonstrated a way to use a Content Security Policy to achieve the same thing. That’s right, you can use a security feature to preform an information leak. Isn’t it great? Here’s how that works:

You start with a Content-Security-Policy (via HTTP header or HTML) that only allows resources from the domain of the redirect page (example.com):

content="default-src 'self' 'unsafe-inline' example.com;"

Then you trigger a request to that redirect page, that would then redirect to another whitelisted domain (www.example.com).

<img src="https://example.com/login?redirect=http%3A%2F%2Fwww.example.com">

So that means unless your redirect page will only redirect to one single full domain, only redirecting to HTML content won’t prevent the issue.

Then all you have to do is listen for the SecurityPolicyViolationEvent DOM event, or use a report-uri with a little server-side scripting (a JavaScript-free alternative) to detect if the redirect happened.

So what options do we have?

Well the simplest solution is often the best one. You can stop doing automatic redirection based on login, in many cases. If a user end up at your login page, prompt them to tell them they are already logged in, and they can click a link to continue to their destination (perhaps with another option to logout and into another account). Note that this means you also can’t auto-redirect someone to the login page if they are not logged in, but instead prompt them that they need to login.

If that doesn’t work, the alternative is to handle it like you would any other CSRF request. Use CSRF tokens to validate the redirect request, and/or check the Origin and Referer headers.

Yeah, the options are less-than-ideal, but given the backwards-compatibility requirements of the web this is unlikely to change.

Cross-Origin Resource Sharing: Mistakes were made.