

Facebook Vulnerability: Like Clickjacking - erickerr
http://erickerr.com/like-clickjacking

======
mkjones
This is Matt Jones, an engineer on the site integrity team at Facebook. We're
the ones who address issues like this one on Facebook.

Ultimately clickjacking / UI redress is a browser vulnerability - it shouldn't
be possible to display one thing and have another receive user interactions.
As some people have pointed out, Firefox's NoScript plugin does a pretty good
job of preventing it. But that isn't to say victim web sites shouldn't do
anything about it.

In the case of Like buttons, they inherently run in an iframe so our
protection on the rest of facebook.com
([http://theharmonyguy.com/2010/03/13/facebook-adds-code-
for-c...](http://theharmonyguy.com/2010/03/13/facebook-adds-code-for-
clickjacking-prevention/)) can't apply. However, Facebook knows the urls these
buttons point to and generally knows or can infer the urls where they are
embedded. When we detect a likejacking site on one of these urls, we block its
url or domain from being liked and prevent future clicks on facebook.com from
going to it.

~~~
photon_off
Hi Matt. First off, thank you for coming forth to make a statement about this
vulnerability. It's nice to see that fb is responding to these incidents, and
since you care, I'll work with you to solve the problem.

But first, let me express how disconcerting I find it for facebook to "pass
the buck" on the blame of this vulnerability. It's not a browser vulnerability
to have personal information be shared by implementing a "1 click publishing"
button via a cross-domain iframe that (often times unknowingly) has a user
logged into another site -- it's a privacy vulnerability that you need to take
care of. As of late, I see no way that I can disable "liking" stuff, and I'm
aware of the vulnerability, so I stay logged out of Facebook as often as I
can.

It's facebook's decision to use an iframe, to publish content to user's news
streams in 1 click, and to allow any website to implement the like button.
It's your decision in spite of knowing that the means of doing so are open to
"vulnerabilities" such as linkjacking. I put "vulnerability" in quotes because
it's not really a vulnerability, now is it? It's a fundamental possibility
based on how HTML works -- links can be invisible! Calling "linkjacking" a
vulnerability is like calling tracking pixels, sessions in URLs, or anything
that can be used for ill purposes, a "vulnerability" that browsers need to
take care of. I'm not buying it. It's part of the design of HTML and you need
to work with it.

You could easily remedy the situation by ensuring the user really means to
publish something. However, I realize you aren't going to change anything
about the "liking" process because it will disincentivize publishers from
including it if it's not as effective. Business first, I understand.

Luckily, I will share with you, for free, how to fix this issue.

You can detect whether or not an iframe is being invisibly dragged by polling
the cursorX and cursorY (which are relative to the browser window itself, not
just the iframe) in conjunction with whether or not the user's mouse is over
the "like" button (simple onmouseover/onmouseout).

If the user's mouse is over the "like" button even as X and Y dramatically
change (optionally, over some unit of time) then the iframe is being
positioned according to the mouse movements. A click on the "like" button
should be disabled, and you should discretely notify your server that the
URL/domain is suspect.

If the attackers were smarter, they'd position the "like" button below the
mouse only on an onmousedown event so that your detection script wouldn't
catch on to the one sudden movement of the "like" button in time for when the
user lifts the button of their mouse.

But, luckily, you'd have me to tell you to ensure that both onmousedown and
onmouseup are fired before actually having the "like" button signal a click.

So, there you have it. A free solution to your problem. That worked out much
easier than posting a puzzle on your jobs page and waiting for people to solve
your problems that way.

PS: For some reason as I read my post I realize that I come off as quite
arrogant and perhaps a bit angsty. I apologize for that... it's almost
embarrassing. I think it's just really late and I felt like being really frank
about the issue. At any rate, you guys should hire me.

~~~
mkjones
The idea of detecting if X and Y are changing while the cursor is over the
button is a good one and actually something we thought about. While it does
help mitigate the case where the attacking site dynamically moves the iframe,
it's relatively easy to position the like button statically and just trick the
user into clicking on its particular location, which would bypass this
strategy (albeit at the cost of a slightly lower clickthrough rate). So I
don't think this is a robust enough fix.

I think it's reasonable to say that clickjacking / UI redressing attacks are a
browser bug - it's addressed in Google's browser security handbook:
[http://code.google.com/p/browsersec/wiki/Part2#Arbitrary_pag...](http://code.google.com/p/browsersec/wiki/Part2#Arbitrary_page_mashups_%28UI_redressing%29).
But regardless - we as a victim site are mitigating the problem.

Do you think there's a better way to offer the one-click liking experience
without an iframe?

~~~
photon_off
Fair point about the statically placed and baited frames. Well, detecting X
and Y would solve the movable case of this, so that's better than nothing.

After reading that handbook link, I'd agree that it is very reasonable to
consider it a browser bug. I suppose I considered it more of an oversight in
terms of iframe specifications, and now am more sympathetic to your situation.

I'm not sure there's a better way to offer a one-click liking experience. If
I'm not mistaken, you have two options: more than 1 click, or be vulnerable to
these attacks.

Personally, I'd use the feature more if it behaved the same way that pasting a
URL into my status does. In this case, it would be 1 click to open some sort
of floating dialog (or a small window like in fbConnect), and another click to
change the title, add a description, or just click "ok".

... pause for 10 minutes ...

Perhaps this might be a solution. An embedded javascript (sourced to your
server) returns a code with a unique key for that user/URL combination (along
with whether or not they have already pressed it), stored in javascript in a
private data structure (an anonymous function, for example). You then embed
whatever HTML you need to display your button onto that page, along with code
to ensure it is being intentionally clicked. On click, you load another js
file, where the unique key is passed via the get parameter. Your server will
process the like, and this file will return the javascript to set the button
as depressed, or to request the user login, or whatever.

The reason that the key is stored in an anonymous function is so the host URL
cannot retrieve this bit. Otherwise, they could simply call the second js file
to automate the user "liking" their page. The calls to your js file, however,
still allow you to get the user's session data. And, of course, you can
execute JS on the host's end to ensure that the click is legitimate..

Is this flawed? What do you think?

Edit: I just realized that "legitimate click detection" would be very
involved. But, still possible.

~~~
mkjones
I think that in the current state we have pretty robust protection against
these attacks. If we see people bypassing it, we'll have to change our tactics
:-).

Both of your suggestions are good, but require us being able to run javascript
on the embedding (parent) page. (To have a floating dialog, we need more than
a small iframe, and both this and a full pop-out go against the 1-click nature
of things.)

While we could do the sort of elementAtXY trickery you suggest in the case of
sites running our javascript, it's also possible to use the like widget just
as an iframe, which breaks anything that requires that the parent site is
running our js.

Even assuming we have parent-page js running, we'd also have to avoid anything
that requires a (high-latency) roundtrip to fb servers just to verify if a
click can happen, as this makes for a very bad user experience for those on
slower connections. I think that could be avoided by generating and sending
the user-url key to the fb javascript in the parent page as you describe, and
communicating that to the like button iframe when it's being clicked (after
determining that it's not hidden) by setting it in a fragment on the iframe,
having the iframe grab it from that fragment, and pass it along for
verification on the server. Though I don't know how the parent frame would be
able to know when a click was happening in the iframe, since only the iframe
contents would receive the onclick, not anything the parent page's dom...
Regardless, it's a moot point because the bare iframe can't be protected this
way.

~~~
photon_off
You're probably right. It's easiest just to investigate any alarmingly high
impressions:liking ratio and see if something phishy is happening.

Then again... the fact that I could unwillingly goatse all of my contacts
(even if you prevent it from happening to too many people afterwards) makes me
not want to stay signed in, at least until I can opt out of "liking" things.

It's late and I'm going to sleep... I'll reply in full tomorrow. Specifically,
I think requiring javascript might not be that much of a detriment, especially
if it alleviates any possibility and concern of fb getting embarrassed by a
surge of clickjacking attacks.

As per the user experience concerns... the js solution wouldn't result in any
worse UX for slow users than the iframe currently does. Either way, it's 1
round trip request needed to display the button, and 1 round trip request to
ensure the button click goes through. In your case it's a round trip to load
the iframe, a round trip once it's clicked. In my case, 1 round trip to get
the JS, which displays the button, and 1 round trip to send the click event
(the changing of the button can be client side and appear instant).

The main concern with a non-iframe solution is that the host page can really
try to screw with your button.. you'd need to make it an image and ensure it's
being displayed correctly (correct size, correct src, etc). But, again, I
think it's entirely possible with not-too-much code.

Alright, I'm going to sleep for real.

------
vinhboy
[http://vinhboy.com/blog/2010/05/31/facebook-man-with-the-
big...](http://vinhboy.com/blog/2010/05/31/facebook-man-with-the-biggest-
trick/) I also wrote about this like 2 months ago, and they still haven't done
anything about it...

=(. Facebook CTO guy, are you around today?

~~~
bkrausz
I'm not sure if this is even possible to fix, given the same-origin policy on
iframes. Facebook can't tell where the iframe is placed on the page, and I
don't think they can tell if it's 'position:absolute'd. It's a tough problem.

~~~
vinhboy
Without testing, I suggest maybe making the iframe do an "alert" -- "Are you
sure you want to Like this page?"

One more step, a lot more security.

Or at the very least make it easier to find things that you have liked ( I am
speaking without actually going to look if its easy to find it... I just
remember it was very hard to find the last time I tried )

~~~
bkrausz
Alert boxes tend to be horrible in terms of usability, but it is the only way
to actually require a second step, since anything else you do will be
constrained to the iframe and you can just clickjack a second time.

I think the solution they'll end up implementing (if they do anything) is an
"I didn't Like this" link that users can click to report false clicks. If a
company gets more than x% of those they get taken down. It's not a legit
solution but should be fairly effective.

~~~
mukyu
They can change the like to a 'pending like' and confirm it next time you
check facebook.

~~~
ctingom
And for "trusted" fan pages they could automatically bypass that.

------
bsnss-mn-cdr
Items like this will always be a never ending battle. Each time one side has
to update their technology to stop something from the other they normally must
gain more authority from the other. In the case of Facebook that will be
asking for more rights into each website that wants to use the 'Like' button
and with the recent privacy issues this will just kick the hornets nest all
over again.

~~~
prodigal_erik
I see it as a battle between "the browser is a reliable tool for reading and
navigating documents on the web" and "the browser is just another UI toolkit
for trusted desktop applications". It can't be both, because any seamless UI
will always be powerful enough for untrustworthy code to find other malicious
tricks like this.

------
mdwrigh2
Unfortunately, the twitter clickjacking attack still isn't fixed. See
<http://seclab.stanford.edu/websec/framebusting/index.php> for an overview of
how that type of defense still can be defeated.

------
qeorge
Its especially bad because of the way profile pages are organized. When you're
viewing your own profile wall posts and status updates float to the top, while
Likes, new friends, and other such ambient updates are further down. However,
other people see the Like front and center on their News Feed.

I noticed this after several friends were liking "10 WORST construction
mistakes", or similar. I asked several about it, and none of them had any idea
it had happened.

------
kwamenum86
Anything in an iframe or under an iframe is susceptible to clickjacking.
Firefox + NoScript does a pretty good job of preventing this.

