DEV Community

Dhilip kumar
Dhilip kumar

Posted on

Why should you use "noopener"? Beware of security Flaws.

Alt Text

TLDR:
Checkout the implementation example here:
Live Demo

Let's Open a url in new tab from within our website

HTML WAY


<a href="https://malicious-domain.netlify.com" target="_blank">Visit Malicious Website!</a>
Enter fullscreen mode Exit fullscreen mode

Okay, here we have a href attribute to a malicious website and target as _blank attribute to make it to open in a new tab.

Let us say that, the user clicks on "Visit Malicious Website!" from the above code. He gets redirected to the malicious website in a new tab.

The flow seems so plain and simple what's the possible Security risk that the user has here?

  • The user is redirected to a domain from your page.
  • At this time, the browser attaches all your window variable's content of your current website to window.opener variable of the malicious website.
    • This is done by Chrome and Firefox browsers which has one of the largest user base.
    • So now the malicious website has access to your website's window, which obviously opens up a security loop hole in redirection of this method.
    • Now the malicious website once it has access to your website's window variable through window.opener it can redirect your previous website to a new Phishing website which could look similar to the actual website you opened and might even ask you to login again.
    • The above change can be done in the malicious website by just writing the following code
  if (window.opener) {
    window.opener.location = 'https://www.dhilipkmr.dev';
  }
Enter fullscreen mode Exit fullscreen mode
  • So the Innocent users get caught in this trap and would provide the login details which could be exposed to the attacker.

How do we avoid this?

A simple way is to add a rel attribute with noopener to the <a> tag.

<a href="https://malicious-domain.netlify.com" rel="noopener" target="_blank">Visit Malicious Website!</a>
Enter fullscreen mode Exit fullscreen mode

What does it do?

  • rel="noopener" indicates the browser to not to attach the current website's window variable to the newly opened malicious website.
  • This makes the window.opener of the malicious website to have null as its value.

So be careful when you navigate your users to a new domain that is not maintained by you.

Not always we open a new tab with a tag there are cases where you have to open it through executing javascript's window.open() like below,


function openInNewTab() {
  // Some code
  window.open('https://malicious-domain.netlify.com');
}
Enter fullscreen mode Exit fullscreen mode
<span class="link" onclick="openInNewTab()">Visit Malicious Website!</span>
Enter fullscreen mode Exit fullscreen mode

Here there is no mention of noopener so this results in passing window of the current website to the malicious website.

The javascript Way!

How to handle such cases when new tab is opened through js?

 function openInNewTabWithoutOpener() {
   var newTab = window.open();
   newTab.opener = null;
   newTab.location='https://malicious-domain.netlify.com';
 }
Enter fullscreen mode Exit fullscreen mode
<span class="link" onclick="openInNewTabWithoutOpener()">Visit Malicious Website!</span>
Enter fullscreen mode Exit fullscreen mode

Here,

  • We have opened a dummy tab through window.open() which opens about:blank, so it means it has not redirected to the malicious website yet.
  • Then we modify the opener value of the new tab to null
  • Post that we modify the new tab's url to the malicious website's url.
  • This time, again opener would have been null, due to which it cannot access the window variable of the first website.

Problem Solved.

But this method wont be possible in older versions of Safari, so we again have a problem.

How to fix Safari's issue?

function openInNewTabWithNoopener() {
  const aTag = document.createElement('a');
  aTag.rel = 'noopener';
  aTag.target = "_blank";
  aTag.href = 'https://malicious-domain.netlify.com';
  aTag.click();
}
Enter fullscreen mode Exit fullscreen mode
<span class="link" onclick="openInNewTabWithNoopener()">Visit Malicious Website!</span>
Enter fullscreen mode Exit fullscreen mode

Here we mimic clicking on an anchor tag.

  • We create <a> tag and assign the required attributes then execute click() over it, which behaves the same way as the link is clicked.
  • Do not forget to add rel attribute to the tag here.

Other facts:

  • When you click CMD + LINK on anchor tag, chrome, firefox and Safari considers makes window.opener of the malicious website as null
  • However, on CMD + LINK on an element where new tab opening is handled through javascript, the browser attaches window variable and sends it to the new tab.
  • By default, the new version of Safari removes window.opener when used with anchor tag for all cases, to pass the window info to the new tab you have to explicitly specify rel='opener'

Checkout the live implementation example here:
Live Demo

None shall bypass your Security.

Follow me may be :P

My Website, blogs and Twitter

Thats all Folks!!!

Top comments (7)

Collapse
 
chillsunfire profile image
Sunfire

I've been using noopener and noreferrer for years now, but never really understanding why. Thank you for the understandable explanation.

Collapse
 
dhilipkmr profile image
Dhilip kumar • Edited

Yes missed them!

Whenever the opener object is defined in the new website, both run with same event loop. (i.e) there is only one process handling both tabs.

May be the approach of creating anchor tag dynamically through js and clicking it is the best approach that considers all cases ,if we want to open the new tab through JavaScript

Collapse
 
chrisachard profile image
Chris Achard

Thanks - I've seen the warning message to use noopener in gatsby before, but never knew why. Now I do!

Collapse
 
dhilipkmr profile image
Dhilip kumar

😃😃✌️✌️

Collapse
 
havarem profile image
André Jacques

Very good to know, I've never come across this before. Thanks a lot :)

Collapse
 
dhilipkmr profile image
Dhilip kumar

😃😃✌️

Collapse
 
marcellothearcane profile image
marcellothearcane

Weirdly, window.opener.open() is blocked by chrome (if it's cross-origin), but not window.opener.location = <url>