Reverse Tab-nabbing — Links and Its Security loop

Reverse Tab-nabbing — Links and Its Security loop

Well, all the webpages in the web became cool because we could link one page to another right ?

This is made possible by the good old ‘Anchor Tag’ (<a>), what could possibly go wrong using an anchor tag? Well, some security concerns are associated with the usage of anchor tags while linking an external resource.

In this article, we are going to discuss the security concerns associated with linking external resources and some patterns for mitigating these security concerns. This is what we would talk about:

  1. Concerns related to noopener

  2. Concerns related to noreferrer

  3. Different ways of handling these security issues

  4. How did we tackle this in smallcase by creating a reusable component?

  5. How do we decide which links should be internal links and which links should be external?


  1. noopener

The first and foremost concern is with regards to noopener. Whenever you link any external resource, and the user clicks on that link and opens that linked website, that linked website’s window.opener property returns a reference to the window that opened the window (i.e, your site). This is true irrespective of whether the link was opened in the same tab or a new tab.

The functionalities exposed by the window.opener is very less especially when the origin of the opener is not the same as the current page, variables and functions on the opener window object are not accessible, But still, navigation of opener window is possible which enables the opening window to navigate the opener window to other location, say a phishing site. This is called ‘reverse tabnabbing’. Basically how ‘reverse tabnabbing’ happens is, suppose a document, let’s name it ‘abc.com’, has an anchor tag with target=”_blank” with href directing to some other document, lets name it ‘X News’, when the ‘X News’ gets opened, the window object of ‘abc.com’ document tab is passed to ‘X News’ tab and it is accessible through window.opener. window.opener is basically ‘abc’ tab’s window object.

What can the ‘X News’ doc do with this reference? There are several things which can be done, one of which is redirection, this opened new tab can redirect the opener window to some other location and the user won’t even notice because the current focus would be on the ‘X News’ tab, and by this ‘X News’ can redirect to anywhere, maybe a phishing site and may ask for credentials or sensitive data from the user.

  1. No Referrer

Whenever we link to an external resource and the user clicks on that link, the referrer header would be passed to the opened page which indicates where the traffic is coming from. This might not look like imposing any security issue, but the issue arises in what all information is being passed in the header.

An example scenario is :

  • the referrer header contains the address of a request,

  • consider a “reset password” page with a social media link in a footer. If the link was followed, depending on how information was shared, the social media site may receive the reset password URL and may still be able to use the shared information, potentially compromising a user’s security.

Other relevant info:

  • All the new major browsers by default set rel=’noopener’ for any target=’_blank’

noreferrer includes the functionality of noopener and it seems to be redundant, but if we dig a little deeper and look into browser support for noopener, we find that there are still some browsers that currently doesn’t support noopener, and also there is no downside in mentioning both noreferrer and noopener.

  1. Different ways of handling these security issues

  • Specifying the values in rel attribute of anchor tag/link tag

    Having rel = ‘noreferrer noopener’ in anchor tag inside external link. This is pretty straight forward, we will not be passing anything.

    example -

  • Referrer-Policy
    The Referrer-Policy HTTP header controls how much referrer information (sent via the Referer header) should be included with requests. Referrer policy can be set for the entire document using meta tag

    In the above HTML, content specifies the referrer-policy. Different referrer policies can be found in mdn docs of referrer policy.

Or we can specify the referrer policy to specific links

Note: referrer-policy is still a working draft and isn’t a web standard yet. can_i_use

  • Exit Page Redirect
    This method involves having an intermediate page where we redirect our users to and from there the user is redirected to the intended. This is the safest and only method to work without any flaw. More on this here.

How did we tackle this at smallcase creating a reusable component?

There is already an eslint rule which warns about using noreferrer and noopener when adding target=”_blank” to any link. We were using that rule, but we realized that devs have to make a decision about using rel=”noreferrer noopener” at every point of usage. This was not easy for every dev to follow, and we wanted to wrap this functionality in a more semantic interface, so we decided to create a reusable component, which would have sensible defaults and make it more declarative for devs to use.

We created a reusable component that would accept the following params as props -

prop nametypedescription
hrefstringaddress to be redirected when the user clicks
childrennodeconsists of the node which is to be displayed, suppose if the user wants an image to link component, etc...
onClickfuncan optional prop function that would be called when the user clicks on the component
nofollowboolthis prop is to decide whether we want the 'nofollow' attribute in rel of the anchor tag
noreferrerboolthis prop's default value is true, and if the user explicitly wants to pass the referrer header, they can set it to false.
targetstringby default, this value would be set to '_blank', and the user can override if he/she wishes.

and the component looks like below

by making use of the above common component, we could make it convenient for devs to take care of reverse tab nabbing.
Note that the noopener is always set because we didn’t find any use case where we wanted the opened window from an anchor to have a reference to the opening window.

Note:

Even when you are opening any window programmatically/via javascript, you’re vulnerable to this, to avoid being vulnerable set the opener to null

however, the above method may fail in safari, for safari support, inject a hidden iframe that opens the new tab and immediately remove the iframe.

  1. It is quite important to differentiate between which links to be considered as internal links and which ones to be considered as external links for many reasons such as analytics, sso, and so on.

    Internal links - links which we are owned by us — in other words, links to the same origin or any resource owned/handled by own organisation can be considered as internal links, its quite safe to pass the header details and even the opener reference since the internal links are those links which are belonging to you/your organisation, so there is not much risk of reverse tabnabbing or sensitive information in header getting leaked. These links may open in the same tab or a new tab.

    External links — Any links which lead to any location which are not owned by us are to be considered as external links, whether they open in a new tab or not.

    One more super important thing to keep in mind is, if your site has content written by your user, you should make sure that the links written by the user in the content are handled for reverse tabnabbing.

Fin.


Acknowledgments:

Huge thanks to Gaurav Gupta without whom this article would not have been possible.


References: