Deceiving Users with the Facebook Like Button

Update: I've written a followup to this post, which you may also find interesting.

Facebook just launched a super-easy widget called "The Facebook Like Button". Website owners can add a simple iframe snippet to their html, enabling a nice "Like" button with a count of other people's "Likes" and a list of faces of people if any of them are your friends. The advantage of this new tool is that you don't need any fancy coding. Just fill up a simple wizard , and paste the embed code in, just like you do with Youtube, etc.

However, this simplicity has a cost: Users can be tricked into "Like"ing pages they're not at.

For example, try pressing this "Like" button below:

This is what happened to my Facebook feed when I pressed it:

Screen shot 2010-04-21 at 10.45.01 PM

I used as an example here to be work/family-safe; you're free to come up with examples of other sites you wouldn't want on your Facebook profile! :)

Important note: Removing the feed item from your newsfeed does not remove your like -- it stays in your profile. You have to click the button again to remove the "Like" relationship.

This works because the iframe lets me set up any URL I want. Due to the crossdomain browser security, the "Like Button" iframe really has no way to communicate with the website it's a part of. Facebook "Connect" system solved this using a crossdomain proxy, which requires uploading a file, etc. The new button trades off this security for convenience.

An argument in Facebook's favor is that no self-respecting webmaster would want to deceive the visitor! This is true, the motivation to deceive isn't very strong, but if I am an enterprising spammer, I can set up content farms posing as humble websites and use those "Like" buttons to sell, say Teeth Whitening formulas to my visitor's friends. Or, if I'm a warez / pirated movie site, I'm going to trick you with overlays, opacities and other spam tricks and sell your click on an "innocent" movie review page to a porn site, similar to what is done with Captchas. I'm going to call this new form of spam Newsfeed Spam.

This is scary because any victim to this is immediately going to become wary of using social networking buttons after the event; and will even stay away from a "Share on Twitter" button because "bad things have happened in the past with these newfangled things"!

I don't have a good solution to this problem; this sort of spam would be hard to detect or enforce since Facebook doesn't see the parent page.

• One weak solution is to use the iframe's HTTP_REFERER to prohibit crossdomain Likes. I'm not sure how reliable this is; it depends on the browser's security policies.

• Yet another solution is to provide the user with information about the target of the Like. e.g. it can be:

  • Shown in the initial text, i.e. "and 2,025 others like this" now becomes "and 2,025 others like "Britney Spears"..." The downside to this is that it can't be shown in the compact form of the button.
  • Shown upon clicking, i.e. "You just liked"
  • (my favorite) Shown on mouseover the button expands to show the domain, "Click to Like"

This problem is an interesting mix of privacy and usability; would love to see a good solution!

Update: I've written a followup to this post, which you may also find interesting.

What other people have to say:

Very interesting post – thanks for sharing your thoughts. I certainly loved how easy it was to implement, even some of the more complex Open Graph metadata, but you raise a very good point.

Checking the referrer (errr, “referer”) header seems obvious to me, I wonder why they’re not doing it.

Sure, the referrer can be spoofed if you can set arbitrary headers, but you can’t set headers on iframe requests anyway (and even XHR explicitly disallows setting Referer)

You could also have report as spam button and rely on algorithms to remove the ones that are pure spam.

Arnab – you are really on to something here, thank you for sharing this valuable information. Today I am both excited and concerned about the next generation of Facebook Connect. In the end I think it will be a winner but there are definitely some significant issues to work out along the way.

Nice post. Very valid points. Very difficult if the various ad network ads start mimicing the Like button on their ad, and users click it thinking they are doing it to like the ad and something completely wild lands up on their profile page. One way (as you have partly suggested) to at least warn the user would be to show some sort of a pop-up (similar to what happens in some sites when you ‘Share on Facebook’ where the user is shown a short sentence on how this will appear on their feed, and then get the user to confirm the same. If that pop-up is served by Facebook themselves, it helps. One click extra but at least in part a more reassuring step for the user.

Nice hack. Beautiful.

Hey, Arnab. It was a nice surprise seeing you on Techmeme. Congrats. :)

Facebook could get around this by proxying the top window’s location through the iframe’s location field. In this approach, the client javascript creates an iframe sourcing some html+js at the server. The iframe’s javascript polls its location field for a set period of time, looking for changes after the URL fragment. Meanwhile, the original client javascript greps the parent window’s location and modifies the iframe’s location fragment to communicate the data.

I hacked together something ugly here: This file just includes a script tag that references a JS file at the “server.” The “server’s” iframe and js are located at a different domain:

Anyway, a crafty website could fake things by calling the iframe directly, and the host should get around this by providing unique session data through the client JS.

At f8 yesterday, one of the presenters said that they would only allow likes to the same domain… obviously that’s not working yet.

From a UX perspective, the user should be allowed to preview the exact contents of the Like post and then be allowed to confirm before posting back to their FB profile. This would do much to eliminate potential trickery.

same-domain won’t solve anything; having the page on, which, for facebook purposes, describes itself as “the borax teeth whitening club” is surely trivial.

it just occurred to me that this is overkill, but proxying via iframe locations to get around cross-site permissions is still a bit fun. :)

Hopefully Facebook gets with the program and provides a solution to this. I’m holding my breath…

This is not a bug, it is a feature
Works exactly the same as electronic voting booths in the US

Your suggestion of this flaw turning people off of social share widgets in general gave me goosebumps.

I would love to see that happen.

This is a really valid point. I’m with you on the third solution, along with having a settings page at Facebook which gathers all my likes and let me remove them there.
Another small deception is having the Like URL point to a popular website (e.g., so the user will see tons of likes and think he’s onto something really popular, which is false.

i think, the new “like” button is only a alpha-like button and zuck published the “feature” a bit too early…

Greeting alex
(wow, many peaple like britney ;) )

Neat post. I would combine mouseover (or better onclick) with the referer: if the hostname of the referer doesn’t equal the hostname of the url passed to FB, then a user gets a confirmation dialog with preview of the passed url. In this case the only ones who will suffer from that will be referer spoofing fans.

Very interesting post also for us here in Germany.

Isn’t there a way to make the link dynamic in the iframe so you don’t have to put a static link into the code on each page?


Sort of. An IFRAME can’t read data from outside its point of view unless the parent page belongs to the same domain. One way to get around this is through dynamic generation of the IFRAME tag with a dedicated script tag. This might be more difficult to style and lay out than with the existing IFRAME based approach. An alternative is what I mentioned a few comments above. This involves proxying data to the IFRAME through its location field. Page layout still involves an IFRAME, but a script runs on page load and sends browsing session data to the IFRAME. To discourage middleman script rewriting in either case, Facebook would probably have to associate a unique session identifier for each script GET and link that to the “Like” submission. That session identifier might have to be further associated with the address of the machine that fetches the script, depending on how things are implemented.

There’s probably a better way to do this dynamically, and as people have already mentioned. HTTP_REFERER goes a long way, if not most of the way there.

Since when did the responsibility of what markup goes on a website/blog become any less relevant?

In the same logic, you could even have put an Addthis or Sharethis or digg or other social bookmarking buttons and still pass random urls to their iframe/dynamic script elements to handle the bookmarks.

These share/tweet/like/vote/“social verb” don’t sprout out on pages out of nowhere via some insanely evil remote security loop hole. They exist in the markup with the site’s consent depending if you’re competent enough to edit the template or using some “third party plugin” that does this for you on every page.

Heck, each & every one of these social-bookmarking plugins that exists for blogs itself could insert their own links, upsells as well. “Related posts” plugins could insert in spammy links in run-time. Gravatar could show bogus visitors. Mybloglog could make bogus visitors. Analytics scripts, Youtube embed codes, Slideshare docs shared within posts, CMS plugins,wordpress blogs, chrome extensions, firefox plugins, toolbars, extensions, themes or greasemonkey scripts, each and every one of them could know:
1) which url the reader is on
2) if the reader is registered with them ( yes if it’s a dynamic script insertion, doesnt have to be an iframe)
3) return random content based on 1 & 2
infact the google analytics / drupal modules installed on this very blog by you for the past x months/years could have change all links on a page to britneyspears.

And the one’s who do breach that trust, that insert these without consent could probably be prosecuted, and the word spread that x plugin that “controls the markup” isnt authentic. So it really isn’t the responsibility of Addthis/sharethis/twitter/delicious/facebook to check what querystrings are passed to it. The discussion if at all there is the need for once, should revolve around the authenticity of who adds this markup to the site in the first place.

And if anything it’s at that stage of “who have i delegated the decision to share responsibility of my markup” where the introspection is possibly required.


Great point. This is exactly why we haven’t implemented it.

About the author:

Arnab Nandi is an Assistant Professor in the Department of Computer Science and Engineering at The Ohio State University. You can read more about him here.

August 2002 : 9 posts September 2002 : 16 posts October 2002 : 7 posts November 2002 : 21 posts December 2002 : 25 posts January 2003 : 8 posts February 2003 : 11 posts March 2003 : 7 posts April 2003 : 21 posts May 2003 : 14 posts June 2003 : 15 posts July 2003 : 4 posts August 2003 : 16 posts September 2003 : 25 posts October 2003 : 15 posts November 2003 : 24 posts December 2003 : 17 posts January 2004 : 6 posts February 2004 : 8 posts March 2004 : 6 posts April 2004 : 5 posts May 2004 : 29 posts June 2004 : 3 posts July 2004 : 17 posts August 2004 : 19 posts September 2004 : 3 posts October 2004 : 4 posts December 2004 : 1 posts February 2005 : 14 posts March 2005 : 17 posts April 2005 : 8 posts May 2005 : 27 posts June 2005 : 73 posts July 2005 : 44 posts August 2005 : 13 posts September 2005 : 3 posts October 2005 : 9 posts November 2005 : 20 posts December 2005 : 6 posts January 2006 : 25 posts February 2006 : 23 posts March 2006 : 36 posts April 2006 : 35 posts May 2006 : 7 posts June 2006 : 22 posts July 2006 : 20 posts August 2006 : 27 posts September 2006 : 15 posts October 2006 : 6 posts November 2006 : 19 posts December 2006 : 3 posts January 2007 : 4 posts February 2007 : 1 posts March 2007 : 3 posts May 2007 : 5 posts June 2007 : 2 posts July 2007 : 1 posts August 2007 : 13 posts September 2007 : 1 posts October 2007 : 21 posts November 2007 : 7 posts December 2007 : 9 posts January 2008 : 4 posts February 2008 : 13 posts March 2008 : 14 posts April 2008 : 11 posts May 2008 : 12 posts June 2008 : 12 posts July 2008 : 5 posts August 2008 : 10 posts September 2008 : 11 posts October 2008 : 10 posts November 2008 : 8 posts December 2008 : 4 posts January 2009 : 6 posts February 2009 : 13 posts March 2009 : 7 posts April 2009 : 7 posts May 2009 : 2 posts June 2009 : 3 posts July 2009 : 4 posts August 2009 : 4 posts September 2009 : 6 posts October 2009 : 4 posts November 2009 : 7 posts December 2009 : 10 posts January 2010 : 3 posts February 2010 : 2 posts April 2010 : 5 posts May 2010 : 1 posts July 2010 : 4 posts August 2010 : 3 posts September 2010 : 4 posts October 2010 : 1 posts November 2010 : 2 posts December 2010 : 3 posts June 2011 : 1 posts August 2011 : 1 posts November 2011 : 1 posts December 2011 : 1 posts February 2012 : 1 posts May 2012 : 2 posts December 2012 : 1 posts June 2013 : 1 posts August 2013 : 1 posts October 2013 : 2 posts September 2014 : 1 posts November 2014 : 1 posts November 2015 : 2 posts January 2016 : 1 posts January 2017 : 1 posts April 2017 : 2 posts