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.
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.
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.
It seems I can't reply to your post (max HN thread depth = 5?), so I'll do it here...
I believe the like:impression ratio for clickjacking sites isn't different enough from the (noisy) norm to make it a usable metric for identifying malicious sites.
We should detect clickjacking sites before you get a chance to goatse your friends. I'm pretty sure our the current state of things does that. At least in Firefox, you always have the option to disable third party cookies, which will disable the like button along with a slew of other, much sketchier, stuff that ad networks and the like tend to do.
You're right that it's possible to do the cross frame stuff without an extra ui-stalling roundtrip - that's what I meant to describe in the above post. I think the bigger issue in this case is determining in the parent page when a click is happening so you can determine if it's legitimate.
I don't believe it's possible for the parent page (or fb's javascript in the parent page) to screw with the button in the iframe - cross-domain policy forbids any access to its dom.
EDIT: Also, in case it wasn't clear, as soon as we identify a domain or url to be bad, it's impossible to reach it via any click on facebook, so even if something becomes bad after people have liked it, we still retroactively protect users. So as long as we've detected that something's bad, you can't accidentally goatse your friends with it even if you do get in a like before we identify it to be bad or before it turns bad.
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.