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>
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 towindow.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 throughwindow.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';
}
- 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>
What does it do?
-
rel="noopener"
indicates the browser to not to attach the current website'swindow
variable to the newly opened malicious website. - This makes the
window.opener
of the malicious website to havenull
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');
}
<span class="link" onclick="openInNewTab()">Visit Malicious Website!</span>
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';
}
<span class="link" onclick="openInNewTabWithoutOpener()">Visit Malicious Website!</span>
Here,
- We have opened a dummy tab through
window.open()
which opensabout:blank
, so it means it has not redirected to the malicious website yet. - Then we modify the
opener
value of the new tab tonull
- 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 thewindow
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();
}
<span class="link" onclick="openInNewTabWithNoopener()">Visit Malicious Website!</span>
Here we mimic clicking on an anchor tag.
- We create
<a>
tag and assign the required attributes then executeclick()
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 makeswindow.opener
of the malicious website asnull
- However, on
CMD + LINK
on an element where new tab opening is handled through javascript, the browser attacheswindow
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 thewindow
info to the new tab you have to explicitly specifyrel='opener'
Checkout the live implementation example here:
Live Demo
None shall bypass your Security.
Follow me may be :P
Thats all Folks!!!
Top comments (7)
I've been using noopener and noreferrer for years now, but never really understanding why. Thank you for the understandable explanation.
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
Thanks - I've seen the warning message to use noopener in gatsby before, but never knew why. Now I do!
😃😃✌️✌️
Very good to know, I've never come across this before. Thanks a lot :)
😃😃✌️
Weirdly,
window.opener.open()
is blocked by chrome (if it's cross-origin), but notwindow.opener.location = <url>