Photo by Shahadat Rahman on Unsplash

How to fix target=”_blank” links: a security and performance issue in web pages

Almost every web page has links which open in a new tab leaving the other web page still available. For example, news agencies will tweet about recent events on Twitter: the tweet contains a short description of the article and a link to see the full story on their web page.

How to fall right into the trap

So, how do you make a link open in a new tab in HTML? This is easy (maybe too easy), we don’t even need to write JavaScript code. All we need to do is adding the target=”_blank” attribute to your anchor and we’re done.

If you’re unlucky, you might have fallen right into a trap and unintentionally created a security and performance issue.

You probably did not see that coming.

Security issue: “tabnabbing”

By default, when you open a web page in a new tab by clicking on a link with target="_blank", this page has now limited access to the linking page. The most critical security aspect I can think of is that you can change window.opener.location of the linking page. For example: a shady news web page uses Twitter to spread some stories. The user on Twitter sees the tweet, then he clicks to read the full story on the shady news web page which is opened in a new tab. Meanwhile, the shady news page can use this embedded script on their page

Phishing is the fraudulent attempt to obtain sensitive information such as usernames, passwords, and credit card details (and money), often for malicious reasons, by disguising as a trustworthy entity in an electronic communication.

Impact on browsing performance

Interestingly, target="_blank" has also an impact on your web browsing performance which I have observed firsthand. Every major modern browser like Chrome and Firefox is multi-process. Due to the synchronous cross-window access the DOM gives us via window.opener, windows launched via target="_blank" end up in the same process & thread. The same is true for iFrames and windows opened via window.open.

A click on a tile will open the page in a new tab.

Which popular web pages are vulnerable?

The issue is well known but has recently became more known in the last few years. Here are some web pages in which this tabnabbing approach works (as of the time of writing this article). I hope these web pages which are used by millions fix this issue quickly:

  • Heroku.com
  • My Nintendo
  • Slack.com
  • Twitter.com
  • Facebook.com
  • united-domains Webmailer (they fixed it when I notified them. That’s the spirit!)
  • dev.to (they fixed it quickly when I notified them)

The easy solutions

There are two solutions to fix these problems. The first solution is to add rel="noopener noreferrer" attribute to every link with target="_blank". noopener is the necessary value to ensure linked pages do not have access to the linking page. Use this approach when you have access to the HTML code and when there are not many occurrences to fix this by hand. Some CMS like WordPress (≥ 4.7.4) do this automatically so you don’t need to take action. The (now secure) example above would now look like this:

<a href=”https://sedeo.net” target=”_blank” rel=”noopener noreferrer”>Go to sedeo</a>
Browser support for noopener according to caniuse.com
var otherWindow = window.open();
otherWindow.opener = null;

UPDATE: identify insecure static/dynamic links early

You can identify insecure links early if you add a lint rule. This way, you will be able to identify insecure links in your HTML. This linter would . Here is the implementation of such a rule for the popular HTMLHint linter:

module.exports = (HTMLHint) => {
HTMLHint.addRule({
id: 'noopener-external-links',
description: 'Links with target="_blank" must have a rel="noopener noreferrer" attribute to prevent reverse tabnabbing.',
init: function (parser, reporter) {
var self = this;
parser.addListener('tagstart', function (event) {
var tagName = event.tagName.toLowerCase();
var col = event.col + event.tagName.length + 1;
var mapAttrs = parser.getMapAttrs(event.attrs);
if (tagName === 'a' && mapAttrs.target && (!mapAttrs.rel || mapAttrs.rel.indexOf('noopener') === -1 || mapAttrs.rel.indexOf('noreferrer') === -1)) {
reporter.warn('Prevent reverse tabnabbing of external links by providing rel="noopener noreferrer" attribute.', event.line, col, self, event.raw);
}
});
}
});
};
if (!environment.production) {
setInterval(() => {
const links = Array.from(document.querySelectorAll('a[target]'));
for (let link of links) {
const target = link.getAttribute('target');
if (target && (!link.getAttribute('rel') || link.getAttribute('rel').indexOf('noopener') === -1)) {
console.error(`Unsafe link ${link} is vulnerable to reverse tabnabbing.`);
}
}
}, 5000);
}

Conclusion

Interestingly, Google does not think of this as a major security issue.

Senior Software Engineer @LeanIX. Co-founder of Sedeo. Passion for software engineering and startups. Looking forward to build great things. 有難うございます。🚀

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store