Hacker News new | comments | show | ask | jobs | submit login
Target=”_blank” is an underestimated vulnerability (medium.com)
183 points by SimplyUseless on May 4, 2016 | hide | past | web | favorite | 53 comments

For anyone that wants to see this in action:

- Open a website, let's say google.com

- Open a console and type in `window.open("http://xkcd.com")`

- Disable your popup blocker and do it again.

- Open a console in the new xkcd window and type in `window.opener.location = "https://news.ycombinator.com/user?id=Cpoll"`

Note that Google quietly turned into my profile page. Now, imagine that it instead turned into maliciousgoogle.com, which looks just like Google, and you can see the attack vector.

Saw this a few times.

First we had pop-ups that opened on top of the current window

Then we had pop-unders that opened behind the current window

Now we have... what? pop-switches? that open your link target in a new window and change the source page to the "pop(-up)" behind your back.

Impressive idea, I opened both windows on purpose so they couldn't be blocked or else I wouldn't get to my content and one was transmogrified to an ad page behind my back.

For anyone who wants to see this defeated:

- Disable JavaScript.

Seriously, seeing all these interesting behaviours just makes me advocate even more strongly browsing the "open Web" with JS off by default. The power of JavaScript is not to be underestimated, and while it makes for some very good things that would be otherwise impossible, I think users should be more aware of and understand the risks that allowing any page to run JS can imply.

I only allow JS for a very small number of sites which I thoroughly trust and require it, and haven't missed it one bit; the fact that it automatically rids a lot of other surprising and annoying things pages can do, besides phishing or exploiting you, is a nice bonus.

(Assuming I'm understanding the exploit correctly, obviuosly:)

Limiting JS to a few sites won't protect you fully from this attack, though it will obviously limit your exposure.

If one of your trusted sites, A, has been compromised by, say, an XSS attack, with the ability to inject JS then this attack can be leveraged to also compromise your access credentials to site B by redirecting your login attempt on site B to a malicious imitation of site B's login page. (Of course this assumes that you already have B open in a tab somewhere and that you opened site A through a _blank link on site B. Mostly I would think that would be a plausible scenario for sites mostly based on user-generated content such as forums, social media, and such.)

AFAICT always explicitly force-reloading any login page should make you a lot safer, but remembering to always do that is perhaps not realistic.

I installed Firefox mobile and then NoScript, just to save bandwidth and battery.

but my god, how the web got better!

practically no ads. no frills. some sites don't work, but then I just move to one that does or allow js there.

Couldn't agree more.

I don't even enable JavaScript for google.com, not since they integrated the pile of crap that is/was Google+ which added 10% usage load on my CPUs.

The web now requires JS to function. I think it's time to take off the tin foil hat and accept it.

Unfortunately, two things can be true at the same time: JavaScript increases security risk, and JavaScript is necessary for a lot of the web.

How is this any different in principle than $.get("page", function(result){document.body = result;}); ?

If the attacker can run the javascript you mentioned, they've already run.

The "benefit" is that it causes a "trusted" tab to change, not a new one that a user might expect to be tainted. If I open a link from HN (for example), read it, and close the tab, I'd expect to be back at HN. If the link changed my `window.opener` url to a fake-HN, I could do some action that asks for a password or some similar data. It's more likely to succeed since the user already trusts the existing window/tab/site.

> PS. Interestingly, Google doesn’t seem to care.

That's not fair. They state it's a problem that is inherent to browsers, not that they don't care about the issue.

Also be mindful of Google's warning regarding the author's workaround:

> in particular, clobbering the window.opener property limits one of the vectors, but still makes it easy to exploit the remaining ones.

I'd be interested in knowing the others. So would I imagine most people reading that page.

I mentioned this on another related thread: https://news.ycombinator.com/item?id=11554080. In short, the solution here only closes one of potentially many other similar attacks: http://lcamtuf.coredump.cx/switch/

The attack I linked to originates from the malicious site and links to the trusted site (the reverse of the attack in this post). There is nothing a site can do to prevent this since there is no way for a linked to site to prevent the linking site from getting a window reference to it. So, imagine a scenario like this:

* trusted site implements the guidance here and links to malicious site.

* The malicious site, detecting that they can't get a reference to "window.opener" immediately opens a new tab back to the trusted site (maybe to the login page if the site has any logout CSRF issues).

* The user is slightly confused, but they were just on the trusted site, so it doesn't feel too strange.

* If the user is super savvy, the look up at the URL bar and are assured that they actually are back in the trusted site (possibly staring at a login prompt).

* the attacker has a reference to the window they opened back to the trusted site. They set a timer for a couple seconds (like the attack I referenced above). After a few seconds they change the trusted site to load a malicious site and/or malicious data URL.

* user "logs in to the trusted site" and gives up their creds.

Re: http://lcamtuf.coredump.cx/switch/, couldn't browsers simply do a better job of showing the address when window.location.href is 'data:text/html;-peak.us/banking_interface/' or any other data URL?

Re: malicious sites linking back to a parent that opened the, could browsers not also disable cross-origin .opener?

Sure...but that is another thing that needs to be added to all browsers; it begins to feel like a game of whack-a-mole. In the end, browsers rely on an admittedly fragile premise...the only thing that guarantees your current location is a persistent awareness of what domain you are on. Most of the time that works for savvy users (normal users have no fighting chance/nor should they be expected to have to do this). But, these various edge cases break the reasonable expectation that the domain I'm on will stay the domain I'm on until I explicitly do something.

In my opinion, the better place for a more holistic fix to this is within Conntent Security Policy. That could, theoretically, address all attacks that somehow obtain a window ref. The CSP policy could say "window-ref: 'none'". That would be a declarative policy that the browser could enforce in any situation where a window ref might be available.

Another benefit of implementing it in CSP is that you could retroactively fix existing sites without having to go back and fix up potentially thousands of links that didn't set the attribute mentioned in this article.

Of course it's whack a mole. Moat things in infosec are, that doesn't mean browsers shouldn't ship with secure defaults or present trustworthy info in the address bar.

Agreed CSP would be a good place to fix.

This game off whack-a-mole feels different. Unlike the typical "memory corruption of the week", this kind of stuff isn't fixed by a simple browser update and inherited "for free" by all sites. And, this kind of fix doesn't enable a browser to ship with a secure default. Instead, it adds a new thing you have to opt into and retroactively add to all existing links on your site. That is a fair bit of work, and adding more and more of those kinds of features for nominal gain is a tough sell. That is a much more painful game of whack-a-mole and isn't an approach that scales well. The CSP solution at least has a potentially simpler scaling solution to the problem.

> this kind of stuff isn't fixed by a simple browser update and inherited "for free" by all sites

Why not? What's stopping browser from disabling window.opener unless CSP specifically allows it?

(totally appreciate there may be something I'm missing here, and thanks for responding)

Unless we are talking about something terribly dire (arbitrary code execution) browser vendors are super unlikely to change behavior that has existed, and potentially relied upon, for many years. The bar for changing existing behavior is extremely high and this kind of attack won't come anywhere near meeting it. So, the only realistic solution is something that a site opts into (or out of depending on your perspective). CSP would at least let the site that is a potential victim protect itself. And, if there was a good reason to let a partner site have window ref (I could imagine something related to payment providers and modal pop up payment flows), they could opt in to that. It would look something like.

window-ref 'self' PayPal.com

Something like that would let the site reference their own windows as well as grant access to a "trusted partner" like PayPal.

Browser vendors do 'phase out' old behavior and phase in new ones. I understand "don't break the web", but as someone else famously replied, "the web is a self healing mechanism". Look at what browsers have done re: forms submitted over HTTP.

A maintained site that relies on window.opener should, after a 24 month period of angry console warnings saying a change needs to be made, actually make that change.

> The newly opened tab can then change the window.opener.location to some phishing page.

This is true, and is a vulnerability I have been looking at for a while now, though I've not actually seen it exploited yet in the real world. For anyone interested, there are some pretty interesting exploits involving pages where an auth token is in the querystring and thus sent in the referer field by the browser. Also, consider what happens when you use an alert() in javascript to yank context back to the now attacker controlled tab...

> Or execute some JavaScript on the opener-page on your behalf…

Not true, this implies the "attacker" can run javascript in the context of the original page. They can only run javascript after redirecting the original page to one they control, so it's not like they can run code on the facebook.com domain, which would be a _huge_ exploit.

What happens if they change `window.opener.location` to a javascript: URI? I'm assuming (well, hoping) it fails to work, but it would be nice to have that confirmed.

At least in chrome, you get the warning:

> Blocked a frame with origin "https://www.google.com" from accessing a frame with origin "https://news.ycombinator.com". Protocols, domains, and ports must match.

When executing

    window.opener.location = 'javascript:alert(1);'

If you do that cross-origin, the script will not be executed, both per spec and in browsers. That would be a pretty wide-gaping security hole if it worked...

I guess this is the trick 99% of porn sites use to do "pop-unders" now. Shouldn't the fix for this be in the browers?

Yep. Open requested link in a new tab, change the previous tab to some autoplay video or fake chat interface. It's not phishing exactly, but it is certainly devious.

To be fair, not all of those chat interfaces were fake. Some are just scripts that connect to real people quickly once you interact favorably. Then they try to sell you on $50 of cam show credits.

Wait, how do you know that? :P "Market research" eh?

Please don't mock fellow HN users.

I wrote that software for several networks of sites.

Looks like an almost verbatim copy of https://mathiasbynens.github.io/rel-noopener/

At Flexport, a security audit revealed we were vulnerable to this. So we made a linter to detect it. If you use React like we do, maybe our linter will be useful to you too: https://github.com/yannickcr/eslint-plugin-react/pull/582

So quite apart from being a crime against usability, now it turns out target="_blank" is a great big security hole, too. I fear this isn't going to be solved 'the flash way' (i.e. by ditching it altogether) but just by making window.opener.location read-only (but maybe only for different domains). One can still dream, though.

I was really surprised to find out that this works in chrome, since the "site-per-process" policy was one of the major ideas that google implemented and advocated - and different processes shouldn't have access to the same memory space.

But then I read this - https://www.chromium.org/developers/design-documents/site-is...

"Most renderer-initiated navigations (including link clicks, form submissions, and scripted navigations) are kept within the current process even if they cross a site boundary. This is because other windows in the same process may attempt to use postMessage or similar calls to interact with them."

This article is incorrect about this being a vector for executing JavaScript (the same origin policy prevents that), but the phishing potential from redirecting the opener page to a fake URL is definitely cause for concern.

Is there a canonical safe way to pop up a link in a new tab/window? This seems like a major bug and hopefully browser vendors will fix it quickly.

Add rel="noreferrer". As you can probably guess, that also removes the referrer, but if you really want to be "safe", you need to do so anyway.

In what world would a cross domain version of this be a good idea? Maybe there's a legit use case within the same domain (think 90's HTML frames), but cross domain?!

Actually thinking about it more, it's same world that connects to remote servers over plaintext telnet. Oh and you don't need to verify your identity either, user's will just say who they are and we'll trust them.

Which points to the fact that target= is a very bad idea in the first place. As a web developer, it's not my concern or business what window/tab combination my reader views a link in (mechanism vs. policy and all). If I decided to hijack the browser's and user's preferred target policy, then yeah, I'm opening myself up to some exposure to what that link does.

Twitter's t.co links seem to mitigate this by issuing a 301 to the actual link thus fixing the `window.opener.location` vulnerability.

I wonder if the reasons for implementing this are related or just good riddance :)

They are tracking links.

For you Firefox users, try the add-on RequestPolicy (https://requestpolicycontinued.github.io/) and before a site opens or redirects to another domain, you'll be prompted (you can make policies around your decision for future instances.)

It seems like there's an easy fix... infer 'rel=noopener' by default on every https site that opens an http site. Or just don't allow http pages to redirect https pages.

It would make scam pages much more expensive while still allowing most legitimate use. And it would be consistent with existing security policies.

Then the scammer can use let's encrypt. The solution should be that window.opener shouldn't work cross-domain.

I wouldn't be surprised if there was legacy software that depended on this behavior. Restricting URL change to same-origin will work much better

This is not a very informative article. It doesn't explain how the attack works (e.g. what is the window.opener object? how can an attacking page modify it? what's the trick and why is it important?).

Read the mdn post I link below as well and it should become clear.


How are rel=noreferrer and rel=noopener equivalent in Firefox?

IIRC noreferrer, besides suppressing the Referrer: header, also does what noopener does. There's a bugzilla entry to implement noopener in Firefox.

What to use instead if I need the link to open in a new tab/window?

I reported this issue to Google, Facebook and GitHub. Google and Facebook were not interested and GitHub was already working on a fix.

Same here. I build a demo for that: https://gist.github.com/mems/df881c9495b6744b650c It's display a fake Facebook login page (just HTML and CSS). You can try with your relatives. How many people fall into the trap?

Applications are open for YC Winter 2019

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact