4

I am not a security expert, so I am hoping that a few of you might be able to tell me if there are any gaping flaws in the security design for my web app. Hopefully I'll be able to explain this clearly enough to get my point across.

I have a website which makes calls to my api. Both use SSL and are hosted in Azure, but have different domains / servers. I am also using ASP .Net Identity 2.0 and OAuth bearer tokens, with a 30 day expiration, to track whether or not a user is "logged-in".

Users can log-in either via the main website, or by using a widget which can be added to ANY 3rd-party site.

To keep things secure, the widget creates an iframe which points to a page on my api server, and all functionality, such as login and transaction processing takes place within this iframe.

The parent page uses postMessage to communicate with the iframe when something needs to happen, but to prevent anything on the parent page from getting access to that token, it only exists within the iframe's local/session storage and is never communicated back up the stack.

So far this all seems to be working as intended, but I've run into a scenario where I now need to communicate the token back to the parent for code running on my website. However, I'm hesitant to do this, as it potentially creates a security hole.

Does anyone have any thoughts on whether this is an acceptable risk for code I control, or if there are any issues with the general approach I've taken?

  • For anyone considering doing this - it is best to avoid the bearer token approach. If you can make use of the authorization code grant flow, the token is stored server side, and is never exposed to the browser (plus for security). With a bearer token approach the token needs to be exposed to the browser. Ref. hueniverse.com/2010/09/29/… – HTLee Jun 21 '16 at 4:40
1

You shouldn't allow your authentication/authorization page to be embedded in an IFrame, because you can't prevent clickjacking attacks that way.

From RCF6749, Section 10.13 "Clickjacking":

To prevent this form of attack, native applications SHOULD use external browsers instead of embedding browsers within the application when requesting end-user authorization. For most newer browsers, avoidance of iframes can be enforced by the authorization server using the (non-standard) "x-frame-options" header. This header can have two values, "deny" and "sameorigin", which will block any framing, or framing by sites with a different origin, respectively. For older browsers, JavaScript frame-busting techniques can be used but may not be effective in all browsers.

Not that the danger here is not that someone overlays an invisible button on top of your site's iframe, but the other way around: an attacker creates an inocuous-looking button like "Display cute kittens" and overlays your "Authorize this app to access all of my data" frame on top of that. When the user clicks the "kittens" button he's actually giving access to his account to the attacker. The only way around that is to not allow your flow in an iframe. Or just assume the risk and live with it.

Appart from that, you should be careful with bearer tokens: whoever holds them has authorization, and they're sent over the wire for every operation. A lifetime of 30 days for something like an access_token is a bad idea.

For your own app you can solve it however you please, oauth2 offers the "Resource owner credentials" flow which is a good option IMHO. But you don't really need oauth here.

For 3rd party websites you should use a server-side flow with short-lived access_tokens and long-lived refresh_tokens that require client authentication (whenever possible)

For user-agent side consumers (native apps) you should use a client-side flow with short-lived tokens and take additional precautions. Or use something different from oauth, oauth is very web-centric.


PS: I'd also like to point out that @HTLee comment on the question is wrong:

For anyone considering doing this - it is best to avoid the bearer token approach. If you can make use of the authorization code grant flow, the token is stored server side, and is never exposed to the browser (plus for security). With a bearer token approach the token needs to be exposed to the browser

"Bearer" is a property of the token that means "whoever's in possession of this string is authorized". It is not tied to a particular flow and in fact the "authorization code" flow will produce a bearer token called access_token (and optionally another one called refresh_token).

The alternative to "bearer" tokens is a MAC Token, which is never sent over the wire. The spec for MAC tokens in oauth2 is not standarized yet.

That's what Eran Hammer's post was about and is only tangential to OP's question.

  • Thanks for the information. I'm not an expert on this, so could you please clarify this a bit? I don't understand how "Clickjacking" applies in this scenario. If I open a "popup" on a page (which is actually an iframe) that points to a "login" page on my secure domain, and all critical JS logic and functionality is contained / executed within this frame (with only limited communication support with the parent/host page via POST MESSAGE), how would overlaying an invisible button in the parent/host page in any way affect or hijack the process in the iframe? – Joshua Barker Sep 12 '16 at 14:56
  • Also, regarding whether to use or not use bearer tokens, I'm not sure if there is another way to accomplish this. Regardless of where the token is stored (server vs client), the end result needs to be that if the user has previously been authenticated using their current computer / browser, that authentication needs to somehow persist for X amount of time (default could be 30 days, but could also be configurable), so that, any other site which also uses my service, would recognize the user as already authenticated (ala, using FB to log-in to different sites) – Joshua Barker Sep 12 '16 at 15:03
  • The problem with bearer tokens is that whoever holds them is authorized without any authentication. The workaround with access_tokens is to give them a short lifespan, and use longer-lived refresh_tokens to obtain new access_tokens when they expire. The refresh_token isn't sent with every request, can be used only once, and in most situations can be authenticated (client_secret). This is considered an awful hack by some people, and the real solution would be to use MAC tokens. Regarding your other question about clickjacking, I'm adding that to the answer, so check back in 5'. – GnP Sep 12 '16 at 15:41
  • @JoshuaBarker see my previous comment and the expanded answer. – GnP Sep 12 '16 at 15:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.