— This post is part of a series of monthly blog posts about all kinds of Security topics for Developers —
It’s been a while ago when I first heard about reverse tabnabbing. Initially I didn’t think much of it, because exploits are not always straightforward. At TOPdesk we fixed any potential issues some time ago, but recently it’s getting more attention. I always applaud it when security topics get more attention, and therefore I’d like to explain here how we approach this at TOPdesk.
“Reverse tabnabbing” you say? What are you talking about? Never heard of this thing. Okay, so apparently it hasn’t gotten enough attention yet. Reverse tabnabbing can easily lead to some nasty phishing attacks. I originally read this article by Mathias Bynens on rel=noopener. It explains (and demonstrates) that if a site has a link to an external domain, and when you click the link, the site on the other domain gets full control over the parent’s window object.
This might be a nice feature when creating some edit-dialog, so that after editing an entity it can automatically tell the window.opener page to reload: window.opener.location.reload(); However, in most cases you don’t want the child-page to know anything about the parent, much less control it.
A classic example would be a message forum, in which a hacker posts a link to his own website. People visiting the forum click the harmless-looking link and will most likely see a page with some boring content. In the background this page will redirect the parent page to a fake login page, which looks the same as the login page the message forum uses. When the users go back to the message forum tab, they appear to be logged out. They don’t think much of it, and fill in their credentials. After submitting the credentials, they get harvested by the hacker and to avoid suspicion the user is automatically sent back to the forum’s main page.
This attack is actually worse than a regular phishing attack, because users don’t actively go to the fake login page. For this reason there’s no real trigger to check if the URL in the location bar is indeed authentic. Also, since TLS certificates are nowadays free of charge, the phishing site can look really secure and safe.
So, what’s the solution to avoid all this nastiness? Basically we should tell the browser to not make this window object available to child pages. Since it can be complicated and error-prone to decide this for each situation individually, we follow the same rule always!
Note the rel=”noopener noreferrer” part. The noopener value tells the browser to not make an opener object available to the linked website. Because some (older) browsers don’t support this, it’s best to add the noreferrer value. The noreferrer tells the browser not to make any referrer info available to the linked website.
If you don’t want to set the noreferrer on every link separately, it’s also possible to add an HTTP header to all your responses. We added the following HTTP header to our reverse proxies:
For more info on this, see: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy
Note that the URL is only filled in after the opener object is cleared. Setting the URL in the beginning allows for a theoretical window (or tab? 😉 ) of opportunity in which the child could theoretically do nasty things, before the opener is finally cleared.
There are also positive side-effects of this approach. Sometimes the child page uses a lot of resources for calculations. Jake Archibald explains that because of synchronous cross-window access, the browser uses the same process for both windows. So, a heavy child process may influence the performance of the parent window. By removing this cross-window link, most browsers will now use separate processes, which results in an improved performance for the parent page in these situations.
Want to ready more?
Want to read more about security? Find all our security blogs here: https://techblog.topdesk.com/tag/security/