18

Lets say you have a JavaScript widget which needs to fire off a request to your web application if and only if the user wants to click on it. You don't want this request to be vulnerable to CSRF so you write an iframe to the page. Based on the origin inheritance rules the parent site won't be able to read the CSRF token. However what about clickjacking (or likejacking )? Because of CSRF you must be within an iframe and there for the x-frame-options cannot help, and the same holds true for frame-busters.

The attacker is going to apply an SVG mask the iframe after the widget has loaded. This mask will make the iframe invisible. At this point the attacker can either resize the iframe to be the size of the page or have this now invisible iframe follow the cursor. Either way whenever the user clicks anywhere on the page, the iframe receives the click event and its game over.

So there is a duality, it seems you are stuck between CSRF and Clickjacking. What the best solution (if any) to this problem?

rook
  • 66,304
  • 38
  • 162
  • 239
  • if you're that worried about it, some kind of captha would work. even changing the click into a double-click, drag, or two different clicks would effectively stop clickjacking. random placement like the window UAC confirm dialog also help prevent robot attacks. – dandavis Dec 31 '13 at 19:39
  • @dandavis captcha's are vulnerable to clickjacking http://www.pcper.com/news/General-Tech/Beware-click-jacking-Captcha-Evil – rook Dec 31 '13 at 19:43
  • did you read the article? that a clever attack on windows using a specific captha provider's default html layout to hide a window feature. it still doesn't bypass the captha, it just attacks windows. That's one reason I don't recommend any external services. My point is that just making something take "more than a click" will effectively stop clickjacking. given the iframe setup, you don't even need a secret answer to your challenge, so it can be validated client-side. – dandavis Dec 31 '13 at 19:49
  • 1
    @dandavis No i didn't really read it, but I've used clickjacking (well UI Redress) to bypass CAPTCHAs. I collected a google bug bounty for this attack, you needed to solve a captcha to delete your youtube account, and made a ui redress exploit that looked like you where signing up for a user account for some forum. Solve the captcha and bam, youtube account deleted! – rook Dec 31 '13 at 20:05
  • then use a "drag to confirm" widget like OSX's installs or mobile phone unlocking. – dandavis Dec 31 '13 at 20:36
  • I updated my answer for the case of the widget being something like the twitter button. – Angular University Jan 04 '14 at 17:10

6 Answers6

6

Clicking on the widget needs to open a pop-up window containing a new page -- an iframe is not good enough, it must be a new window -- which is entirely under the control of your web application. Confirm the action, whatever it is, on that page.

Yes, this is somewhat inelegant, but the present Web security architecture doesn't give you any better options.

zwol
  • 135,547
  • 38
  • 252
  • 361
  • I agree this proposed solution is ugly, but as far as I can tell this is the only real solution to the problem I have described. Good job. – rook Jan 14 '14 at 10:49
  • 1
    If you're willing to trade away prettiness in order to gain speed and ease of use, a simple JavaScript `confirm("Do you really want to {do whatever}?")` popup would also work as an alternative to loading a whole new browser window/tab and loading a page. – Mark Amery Jan 16 '14 at 18:40
5

There is no way to prevent request forgery while under a clickjacking attack. No CSRF defense exists that can withstand a clickjacking attack, because there is no way to distinguish a real click from a fake click on the client side.

OWASP mentions in their CRSF prevention spreadsheet that one of the preconditions for the CSRF token defense to work is that no XSS attack is underway.

In my view this should also include clickjacking, as the CSRF token even hidden inside iframe cannot defend against clickjacking. The request is being forged by a direct user click.

So in the end we are not really stuck between CSRF and Clickjacking - CSRF defenses are meant for a different type of attacks where there is a lot less power on the side of the attacker.

So towards the questions you mention concerning clickjacking and CSRF:

  • What is the best solution (if any) to this problem? - The best defense for clickjacking on the client side is to open a new browser tab or a resized browser window with a page from your site and confirm the action there, as @Zack mentions. This is what the twitter button does, and there cannot be request forgery in this scenario either.

  • So there is a duality, it seems you are stuck between CSRF and Clickjacking - The CSRF defenses are not meant for cases like XSS or clickjacking attacks, they are effective only against less powerful attacks (email with malicious link, post malicious link in forum etc.)

Angular University
  • 42,341
  • 15
  • 74
  • 81
  • There are enough ways to puncture the same-origin policy for iframes that I feel this recommendation is unsafe. – zwol Jan 05 '14 at 04:58
  • @Zack The attacker could simply fire the `click` event if the widget wasn't in an IFrame. – SilverlightFox Jan 05 '14 at 14:46
  • That's right, I updated the reply with the recommendation of opening a new window and the reason why CSRF defenses don't apply in clickjacking scenarios – Angular University Jan 05 '14 at 16:13
4

There is no good programmable solution on clickjacking. Some companies sue spammers as a defense to clickjacking. Others choose to show popup windows once user clicked inside iframe, although it degrades user experience, especially in case of single-click-button. This is exactly what Twitter do for the “Retweet” button. Facebook currently deploys this approach for the “Like” button, asking for confirmation whenever requests come from blacklisted domains. I’ve heard that Googlebot perform some clickjacking heuristics while indexing pages with its “+1” button (checking computed styles, elements overlapping and so on)…

Pavel Podlipensky
  • 8,201
  • 5
  • 42
  • 53
-1

--UPDATE-- When you say "widget", if you mean something outside of your application that un-authenticated people interact with then disregard this answer. I reread your question and you never really state what you mean by "widget". We have all kinds of "widgets" that are with in our application. I thought that's what you were talking about, everything inside an application that only authenticated users were interacting with. If that is the case then this answer is what OWASP recommends.

--Original Answer-- "You don't want this request to be vulnerable to CSRF so you write an iframe to the page." No, don't make an iframe, that way you can do the normal OWASP recommendation for protecting against Cross Site framing.

To protect against CSRF hash some value(s), include it in your form (or ajax POST data), then check the hash value on the back end. If it matches it's from your site. The more specific data you can put in the hash the better.

Example: When a user signs in you can create a long random string and tie that to their session. This string must never be visible on your site or when viewing the source. Then lets say the user pulls up some specific record that they want to edit. You could then take that users long random string you created, append that records primary key to it, then hash them. The result of that hash you can include in your form as a hidden. Then on your backend before you do anything you check for the presence of that hidden, if it doesn't exist, abort. If it does exist, take that users random session string and the clear text primary key they submitted, hash them, if it matches you know it's from your site.

And it's easy to add this everywhere even if your site is already written (assuming your site has some single piece of code included on all pages, like a footer). Make the hashed value and place it in a hidden div somewhere in your footer. Then you can use jQuery to dynamically add this hash value hidden to all forms on the page. And you can use jQuery.ajaxPrefilter to add it to all ajax POSTs automatically in case you are doing a ajax post and not a normal form post. We've protects some very large sites that were already coded this way.

https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet

If this sounds like that path you want to take I could show some of the jQuery code for doing it. As far as what your are hashing, how you want to check it on the backend, etc... that all depends on if you are using ColdFusion, PHP, PL/SQL (psp) etc... I can point you in the right direction if its one of those.

gfrobenius
  • 3,987
  • 8
  • 34
  • 66
  • This would not stop the attacker from getting at the CSRF token if they included the widget on their own site. By attacker I'm assuming a web site owner that wants to harvest "likes" for their own site by including malicious client-side code along with the widget. – SilverlightFox Jan 05 '14 at 14:51
  • You are correct. Is that what he means by "widget"? I was thinking this was a closed application and it was a "widget" within itself. If I misunderstood then disregard. I'm was talking about a web application. – gfrobenius Jan 05 '14 at 19:29
  • "... you don't want this request to be vulnerable to CSRF so you write an iframe" - unfortunately, that's not complete protection since all cookie/nonce based attempts can be circumvented. Either fix the server with the malicious code or challenge the user (for example, require re-authentication during a high value transaction). – jww Jan 18 '14 at 14:26
-1

I think I understand what you're doing. You want to allow any site to iframe your widget, thus an attacker has complete control of the parent's source code and can create clickjacking routines to force users to click the widget.

So the iframe would be able to employ a CSRF token, as it should, which will protect from this type of attack so long as the parent frame is unable to read the token.

Clickjacking, as I am sure you know, is a completely different type of attack than CSRF and needs a different defense.

Really, if the widget is super important than implement 2-phase authentication. Use http://twilio.com to call the user and have him input a pin. Or send an email to the user with a verification link. Or ask the user to verify the action next time the user logs into your widget's website.

If you had control of the parent frame, then you would have more options. It would then be a XSS protection matter.

Update after the correct answer has been selected

So my approach to protecting against clickjacking is a bit overboard. Looks like it can be protected using a popup window with a confirmation action.

Brian McGinity
  • 5,777
  • 5
  • 36
  • 46
  • "So the iframe would be able to employ a CSRF token, as it should" - unfortunately, that's not complete protection since all cookie/nonce based attempts can be circumvented. Either fix the server with the malicious code or challenge the user (for example, require re-authentication during a high value transaction). – jww Jan 18 '14 at 14:24
  • CSRF protection cannot be fixed by changing malicious code, you are getting CSRF mixed up with XSS. Web developers need to protect CSRF, XSS and Clickjacking--these are 3 grossly different attacks and each require and different means of protection. – Brian McGinity Jan 18 '14 at 16:05
  • " you are getting... CSRF mixed up with XSS" - the malicious code has to come from somewhere. In both cases, the server with the malicious code has to be fixed. And it likely stems from a XSS (unless the developer wrote the malicious code and hosts it). – jww Jan 18 '14 at 16:19
  • the CSRF malicious is coming from the attacker who creates a malicious url and tricks the user to click on it. – Brian McGinity Jan 18 '14 at 16:25
  • "the CSRF malicious is coming from the attacker " - Agreed. – jww Jan 18 '14 at 16:26
  • The attacker tricks the user to visit a perfectly valid url. The attackee just happens to be logged into a website and carries out the action in url without his knowledge. The server says, "this guy gave me his session cookie, so what the heck--transfer $50,000 to the attcker's bank account." The next day the attackee looks in his bank account and says "I did not do that." and calls the bank. The bank says "well at 3:14pm you were logged in to online banking and clicked the transfer money link." – Brian McGinity Jan 18 '14 at 16:41
  • CSRF can occur on websites which have 100% XXS protection. And the server is executing perfectly valid code under the authority of attackee session cookie. – Brian McGinity Jan 18 '14 at 16:44
  • If the website had a XSS vulnerability, the same attack might go something like this: Say the online bank has a user messaging portal with an XSS vulnerability. The attacker creates a message with a – Brian McGinity Jan 18 '14 at 17:01
-1

Because of CSRF you must be within an iframe...

No. You cannot remediate CSRF with form cookies and other nonce tricks. It does not matter where you put them.

So there is a duality, it seems you are stuck between CSRF and Clickjacking. What the best solution (if any) to this problem?

To remediate CSRF, you have to remove the threat by fixing the server that has the injection or malicious code, stopping the phishing email, etc. In the absence of a benign environment, you need to re-authenticate the user (or provide another challenge/response to ensure an interactive user). See:

Te remdiate Clickjacking, utilize X-Frame-Options or frame-breaking code in Javascript. But I don't think either are foolproof. See:

jww
  • 97,681
  • 90
  • 411
  • 885
  • CSRF cannot be fixed by fixing malicious code, you are mixing up CSRF and XSS. CSRF occurs when you are logged into your bank account with a valid user/pw/session cookie and then you click on a CSRF url in an email (or another website you are viewing in another tab) which directs your browser to the banks transfer money post handler--the same as if you clicked on the transfer money link. – Brian McGinity Jan 18 '14 at 16:20
  • "... you click on a CSRF url in an email" - that's not the only CSRF vector. – jww Jan 18 '14 at 16:21
  • Sorry Brian, I'm not sure what you mean. – jww Jan 18 '14 at 16:24
  • CSRF happens when the user is logged into a website and the user is tricked to visit a url he did not intend on clicking. Because the browser is logged in, the action occurs by the full authority of the user without him knowing. The url can come in an email--very common, or in a link which the user is viewing in another website. This is hard to summarize in 600 characters--sorry... It is hard to explain to even web developers. The best thing to do is to create your own CSRF attack url on your own website to fully comprehend it. – Brian McGinity Jan 18 '14 at 16:33
  • "This is hard to summarize in 600 characters--sorry" - No, my bad. I did not understand that was your point of that comment. – jww Jan 18 '14 at 16:38
  • Brian - out of curiosity, did you take the time to read OWASP's [CSRF Cheat Sheet](https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet)? – jww Jan 26 '14 at 10:13
  • Yes, I've read it. I encourage you to construct a CSRF attack on a website you control to see how to prevent it. – Brian McGinity Jan 26 '14 at 14:47
  • Brian - I work with pen tester who break the cookie/token/nonce measures. Its especially easy to break SOP if an external server has XSS (but there are other threats as you noted). That's why I am insist on the challenge or re-authentication. – jww Jan 26 '14 at 15:08
  • noloader, I think you're saying that if a site has an XSS variability, then an attacker can break CSRF protection? If that's what you're saying, I agree. The attacker just needs to know the CSRF token. If OTOH, there is not a XSS variability, then the CSRF token does protect CSRF attacks (as far as I know). – Brian McGinity Jan 26 '14 at 15:39