We have an application outlined below. The UI is provided from a safe domain https://aaa.com, and hosts script from the same domain.
It loads client site https://client.com to an IFRAME. This site can't be trusted and might contain malicious XSS as it's code quality might be generally lower than our application.
The site loads another trusted script from our second domain https://bbb.com. This script could also originate from https://aaa.com if necessary. Both aaa and bbb scripts call REST API from aaa.com, and need security token for that. Security token is obtained by login to UI from the top window on domain aaa.
We need to establish a secure channel in order to pass the security token from the private closure in browser window (scriptA.js) to the private closure in our script in IFRAME (scriptB.js)
As client site is a different domain, we need to use postMessage API for communication of the scripts. Ideally we would like to pass trusted message like "Hey, I am scriptB, send me the token encrypted with this key (assymetric encryption public key generated for that single event), and let scriptA to send encrypted key that malicious XSS can't read".
However the malicious XSS might also fake being scriptB as it sits on the same domain, and send such message earlier with its own key and listen the token from response.
The question is how we could ensure that the request message can be verified in scriptA that it is sent from script loaded from https://bbb.com, and not from XSS loaded from client.com or other domain, or what other ways of secure communication could be used to securely pass token from scriptA to scriptB.
Any suggestions?
Just to let potential visitors know. We didn't come up with a solution to this exact problem, because any means of securing such communication include CORS, which is only usable when you use cookies for authorization. If the communication doesn't involve cookies, attacker server can be used as a forward proxy to bypass any CORS measures included.
Unless the postMessage would include URL of the script (not the hosting window), there seems to be no way to secure such communication and prevent XSS from mimic the target script.
The way we solved it in the end was based on the following assumption:
Even if the token was secured, the malicious XSS can still emit keyboard and mouse events and this way manipulate with the content the way user could in that given view.
For this reason, we have chosen to wrap the previous more general token as a claim to another token, which is generated by server API called from the parent window context by scriptA (which is secured), and restricts the possible user actions only to ones that can be done by the user actions. This token is the validated on the server which scriptB calls.
This results in a fact that even if XSS would steal the token from the message, it couldn't do more than it could simulating the user actions by faking keyboard and mouse events. In addition to that the token is time limited, so even if XSS steals the token, the attacker cannot preserve it in order to manipulate the same data externally later.
In the end a security bug at client side only compromises his own single page, and not the whole infrastructure.
Related
I am trying to embed facebook auth into my application.
My initial effort was to login in browser and obtain code. I pass this code back to my api and obtain access token (that stays with the server) and route all my requests to FB Api through my server. Seemed totally secure to me as my client has no information to be able to make authorized calls to FB as my app.
I however have been looking at FB Javascript SDK to avoid writing code for dialog opening and closing and noticed that it allows me to getLoginStatus and returns me the access token. Also, I went over FB auth flows in their documentation and they say that client-server hybrid flow is okay to do where server actually gives "Long lived access token" back to the client and advises me to use HTTPS (fair).
Now all this gets me thinking if this is a security concern. Can't I as a potential hacker inject some javascript into the user's webpage that could either a) make a getLoginStatus and get the access token or b) just get the access token by making a request to my api server and get the access token and then use that to post (assuming that user authorized my app to do so) to facebook as if my app was doing it?
I am a security newbie and maybe overlooking a bunch of stuff here but could someone help me understand what I'm missing?
Thanks in advance!
PS: I do know I can enable further security to ensure that I need the app secret every time I want to make a request which the client can't do as that information will never be available on client side.
I am not a security expert, just some thoughts: in your question, you are assuming that the hacker somehow injects the script into the webpage in the user browser using malware and that script then interacts with the data you have client-side.
Now, if we imagine this actually happened and the evil script has full access to the web-page data, even if you don't have the access token on the client, what prevents the evil script to make requests to your server and interact with facebook through your server?
Moreover, if the user opens facebook itself and authorizes there, the evil script could be injected into facebook page and do any actions on behalf of the user, just sending the requests to facebook server.
This way, it looks for me that if the situation you describe happened, it would not really matter if you storing the access token client side or not - anyway the evil script will be able to do it's job.
Practically, if you are worried about security - first carefully check all the facebook docs related to authentication and security and follow their recommendations. Second - search for common known attack vectors and recommendations of how to avoid security risks in your application.
If the user already has malware on his computer which is able to alter browser behavior (like inject additional scripts into pages), you probably can't do much about it.
You can only get your access token if you have a valid redirect URI which equivalent to your Site URL on your facebook application settings..
also, it needs permissions before you can post using the facebook access_token.
You can check the API calls at https://developers.facebook.com/tools/explorer/
I would like to create a secure postMessage connection (origin safe), with an Iframe that is created at runtime.
Current state:
I have a script, that generates an iframe with a specific domain (domain.b.com in the example below). I want that iframe to receive messages only from the parent domain (the page that included my script). Since the parent domain is unknown at runtime, I'm thinking of a "Handshake" process as described and illustrated below:
Wait for Iframe to be loaded.
Send postMessage from the parent domain with it's origin.
Set the allowed origin to be the 1st received origin
Edit:
More Info:
On my server I have a whitelist domains (for example domain.a.com, any.domain.com, domain.b.com)
My Goal is to integrate with some of my clients (for example domain.a.com , domain.b.com)
Once integrated I want to prevent hackers injecting Iframes that can listen to sensitive information over postMessage
I want to avoid checking the whitelist, I prefer to give some acessToken, but not sure what is the right flow.
Example 1:
Example 2:
Is that the right way to implement it?
As mentioned here, you should not expect the parent's origin to be sent to you in postMessage's parameter. Instead:
If you do expect to receive messages from other sites, always verify
the sender's identity using the origin and possibly source properties.
Any window (including, for example, http://evil.example.com) can send
a message to any other window, and you have no guarantees that an
unknown sender will not send malicious messages. Having verified
identity, however, you still should always verify the syntax of the
received message. Otherwise, a security hole in the site you trusted
to send only trusted messages could then open a cross-site scripting
hole in your site.
And once you have the main frame's URI in your iframe, you can verify its authorization with a simple AJAX call to the server. In my point of view, a server call is inevitable and one way or another you will make such a call.
There are other ways to know who is including your iframe but they are not relying on postMessage. For instance if you are using PHP, you can check $_SERVER['HTTP_REFERER'] to see who is requesting your iframe even before it is sent to the browser. Yet there are ways to referrer spoofing as well.
If your application requires a solid bullet proof solution then server to server communication is your way. In this scenario, each client of yours has a username and password and the web server who is going to serve the main page should ask for a one time pass token from the web server who is serving the iframe (this is a server to server communication). And then use the token in the iframe's URL to be sent back to the server generated it. Here's a step by step of this scenario:
End user asks for the URL http://customer.com/main.php.
While main.php is executing and populating the response, it also
connects to
http://you_website.com/generate_token.php?username=cutomer1&password=123
and gets a one time pass token token1.
The response is returned to the browser containing an iframe with URL http://your_website.com/iframe.php?token=token1.
In iframe.php you verify the token1 to see if it is valid, and
, at the same time, you are authenticating the requester without actually asking
for his username and/or password (since you know who you have
generated the token for).
Such tokens are usually deleted once used (one time pass) and they also usually come with an expiration data. But that's up to you and your application.
If I build an SSL'ed API that authenticates with a session ID held within a cookie, adds a nonce as a query parameter, and always responds with a JSON 'Object' response (as opposed to a JSONP-style response with a callback), is it secure in general, and in particular against XSRF?
The intent with such an API to only have it available to pages on my own domain, and to be free to expose private data (such as username and emails) through this API (but not be consumable by other domains)--and retain a reasonable amount of simplicity for developers on the team.
Let me at least share what I understand about this approach, and why I think it's secure. Please enlight me if wrong!:
A <script> tag dropped on a 3rd-party domain to our site would send my cookies, but would not be able to parse the JSON object response (and the response would always deliberately be a JSON object at the top level). Also, I need to make sure that API calls that affect state on the server are all protected by non-GET method access, because <script> tags must use GET and so can not cause havok by attempt to call state-changing calls (in other words, the API would be adherent to REST in so far as HTTP methods go). Also, I deliberately do not support JSONP because it would be a security hole.
Man-in-the-middle used to hijack cookies (the session) is not a concern because I'm using SSL with valid certificates.
Replay attacks are a temporally limited concern because of the use of a nonce will limit how long one could send in a replay of an HTTPS request, because the server will make sure that the API call is only valid for a small amount of time in a typical nonce-validating way.
XMLHttpRequest can not make cross-domain calls, so it can't request anything from my site.
CORS (Cross ORigin Resource Sharing) is not of concern because I don't have a crossdomain.xml file or any other advertisement of cross-domain support associated with HTML 5.
An iframe in a 3rd-party site doesn't matter because even though it can load my page graphically, the host site can't access any data within that iframe, and because I've made no attempt to support cross-domain iframe communication (so they can attempt to set # on the iframe URL like folks do to enable communication between cross-domain iframes, but my page won't be responsive to it).
EDIT:
A nonce would also protect against even cross-domain GET requests (i.e., <script> tags) as russau says. In thinking on that specifically, I like the idea of asking for a nonce in a 'POST' API call that is not itself nonce protected; it should be the case that only XmlHTTPRequest's on the same domain can then generate a nonce to begin with. This seems to be a simple way of making the generation of nonce's developer-friendly. (i.e., nothing server-side for the website/javascript developers--just ask for your nonce from the same API you are using to develop against, and make requests with that nonce until you get a 'bad nonce' response--then ask for a new one, and repeat.
The only attack I can imagine is DNS rebinding. If your webserver is configured properly (a name-based vhost should be sufficient) you should be pretty safe though.
We have a "widget" that runs on 3rd party websites, that is, anyone who signs up with our service and embeds the JavaScript.
At the moment we use JSONP for all communication. We can securely sign people in and create accounts via the use of an iFrame and some magic with detecting load events on it. (Essentially, we wait until the iFrames source is pointing back to the clients domain before reading a success value out of the title of it).
Because we're running on JSONP, we can use the browsers HTTP cookies to detect if the user is logged in.
However, we're in the process of transitioning our system to run realtime and over web sockets. We will still have the same method for authentication but we won't necessarily be making other calls using JSONP. Instead those calls will occur over websockets (using the library Faye)
How can I secure this? The potential security holes is if someone copies the JavaScript off an existing site, alters it, then gets people to visit their site instead. I think this defeats my original idea of sending back a secure token on login as the malicious JavaScript would be able to read it then use it perform authenticated actions.
Am I better off keeping my secure actions running over regular JSONP and my updates over WebSockets?
Websocket connections receive cookies only during the opening handshake. The only site that can access your websocket connection is the one that opened it, so if you're opening your connection after authentication then I presume your security will be comparable to your current JSONP implementation.
That is not to say that your JSONP implementation is secure. I don't know that it isn't, but are you checking the referrers for your JSONP requests to ensure they're really coming from the same 3rd-party site that logged in? If not, you already have a security issue from other sites embedding your javascript.
In any case, the 3rd-party having an XSS vulnerability would also be a very big problem, but presumably you know that already.
Whether you are sent cookies during opening WebSocket handshake by browser (and if so, what cookies) is not specified by the WS spec. It's left up to browser vendors.
A WS connection can be opened to any site, not only the site originally serving the JS doing the connection. However, browsers MUST set the "Origin" HTTP header in the WS opening handshake to the one originally serving the JS. The server is then free to accept or deny the connection.
You could i.e. generate a random string in JS, store that client side, and let that plus the client IP take part in computing an auth token for WS ..
I like the way Google Maps' api is consumed, using a script include, but I'm worried:
My api is "semi-private", that is, accessible over the internet but should allow for secure transmission of data and some kind of authentication. The data should remain private over the wire, and one consumer shouldn't be able to get at another's data.
How can I use SSL and some kind of authentication to keep the data secure, but still accessible "horizontally" from a plain HTML page with no server-side proxy required? Do I need to manage keys? How will the keys be posted to the server without being intercepted? Can I use OpenId (or some other 3rd-party authentication) to authenticate api users, or do I have to create my own authentication mechanism? I've been all over Google and can't find a good guide to designing and deploying my API securely.
Right now I'm using REST and AJAX to consume them, but cross-domain calls are impossible. Any help or a pointer in the right direction would be much appreciated.
I'd probably use a dynamically-generated script tag with an SSL URL that included a key in the query string that was public-key encrypted. The server would use the private key to decrypt the query string parameter and return script that included the relevant information (or didn't, if the key was invalid). Or something along those lines. But I'll admit that I haven't actually had to do it in practice.
I'd also look for prior art, like Amazon's S3 service.
So:
User provides secret
Client-side code uses public key to encrypt the secret
JavaScript appends a script tag that includes the URL
Server handles the script request, decrypts the secret, checks it, and sends back the relevant response.
You may well need two cycles, because otherwise the request to the server could be re-used via a man-in-the-middle attack. That would be:
JavaScript appends a script tag that requests a unique key (probably with some confounding information, like the source IP and some random further key)
Server responds with a one-time key tied to that IP
User provides secret
Client-side code uses public key to encrypt the secret, including the unique key from #1
JavaScript appends a script tag that includes the URL
Server handles the script request, decrypts the secret, checks it, and sends back the relevant response.
The response could well be encrypted (to some degree) using the random key included in #1
None of which I've actually done. (Or have I? BWAa-ha-ha-ha...) FWIW.
OAuth might help with this situation by having the user login to the 3rd-party application and allowing your application to access the 3rd-party on their behalf by using a request token when you make xhr requests. http://oauth.net/documentation/getting-started/
========
The reason for using a server-side proxy boils down to the Same-origin policy built into web browsers: http://en.wikipedia.org/wiki/Same_origin_policy
Essentially the browser only allows requests to be made to the address in which the page comes from (e.g. facebook.com can only make requests to facebook.com URIs). A server-side proxy solves this issue by making requests to servers outside the current origin. Server-side proxies are also the best practice for making requests like this.
Check out the opensource javascript Forge project. It provides a javascript TLS implementation that allows secure cross-domain xhr requests. It might be of use to you:
http://digitalbazaar.com/2010/07/20/javascript-tls-1/
http://digitalbazaar.com/2010/07/20/javascript-tls-2/
https://github.com/digitalbazaar/forge
One potential solution:
Set up an Apache server to run your site.
Get an SSL certificate for your site.
Install the apache mod that comes with Forge to setup a cross-domain policy that allows other sites to access yours.
Host Forge's TLS implementation on your site along with your site's certificate in PEM format.
Tell other sites to include the javascript from your site and use it to make secure calls to your site to do whatever it is you want to.
(3rd party) Page uses OAUTH or something similar to authenticate the user and get a token from your server.
Page loads an IFRAME from your server via SSL passing the token along for authentication.
The IFRAME can communicate securely to your server via SSL
Use easyXDM or something similar to communicate between the IFRAME and the 3rd party page, using some limited RPC-like or socket-like API you create.
Or if you really don't trust the third party - do your authentication inside the iframe (no need for oauth then, just use a plain html form) and communicate anything the outer page needs to know about the user using easyXDM.
Not too sure of what the question is exactly, I take it you're attempting to do a jsonp-like call to [https://secure.com] in order to process/display data on [http://regular.com]?
Can the two servers talk to each other? How about something like this:
User logs in on [https://secure.com]
Upon authentication, secure.com generates an token (lets call it syntoken) and passes it directly to regular.com (server-to-server), maybe like a session_id, some arbitrary message, and an otp cipher (lets call it syncipher).
Broswer receives a session_id cookie, and Secure.com then redirects the browser to http://regular.com/setcookieandredirect?session_id=blabla&otpencryptedsynmessage=blabla
Regular.com looks up otp cipher using session_id as a key, and decrypts otpencryptedmessage "blabla."
If decrypted message matches the original message in the syntoken, we can verify user is logged in [regular.com] and regular.com generates another token (lets call it acktoken, lolz) and passes it directly to [secure.com], consisting of session_id, some arbitrary ack message, and a different otp cipher (lets call it ackcipher).
Regular.com then sends the browser a cookie consisting of otpencryptedackmessage (let's name this cookie "verified_session").
Finish loading the page.
From there, you can do jsonp-like calls to
https://secure.com/getscript.js?query=dataname&verifiedtoken=(verified_sessions_cookie_value)
where secure.com/getscript.js will take the verifiedtoken, lookup the ackcipher based on the original cookie session_id sent by [secure.com] as the key, and decrypt the otpencrypedackmessage. If the decrypted message matches the ack message, render the script file.
It's kinda like a 3-way handshake. The secret sauce is that the servers have to be able to talk to each other directly to pass secret keys discretely. You don't have to use the same session_id for both servers, I was just using that as an easy point of reference to find a way to access the syn/ack otp ciphers. The ciphers must be completely hidden from public.