How is window.postMessage() "secure"? - javascript

Please bear with me, I have only some web development experience. In the window.postmessage() documentation syntax is shown for listening for the event caused by postmessage() on the listening page. It is explicitly stated for security reasons that when the event listener is triggered, event.origin should be check to ensure it comes from an expected host. Typically done in the fashion:
if ( event.origin == somehostname.com) {}
Where I get confused is why a malicious user can't just pause the code using a breakpoint and modify the some hostname.com value. This same thing probably applies for the postmessage() call itsself as well for the target origin parameter. How does this provide any "security" when someone could just go edit the string value before it ever happens?

Your theoretical malicious user already has full access to the client-side of both websites. They don't need postMessage to access the data from either of them.
The Same Origin Policy is designed to stop a malicious website from accessing data from a different website using the credentials of the user of the browser (who has been tricked into visiting the malicious website).
postMessage can limit which origins are allowed to read the messages it sends, so if a website used it to send a message containing confidential information, it can mark the posted message as being for some-trusted-website.com which would prevent the malicious website from reading the message.

A "malicious" user could, certainly, make the client-side code do most anything they want, such as leaking information [that they already have access to] to another website, via window.postMessage or just by copying it and pasting it into an e-mail.
In your follow-up comment, you describe "we create a malicious website ready to receive some confidential info" as the threat model. That's a different thing entirely.
Yes, any website that's window.postMessage on sensitive data ought to do at least one of the following to be secure:
Check the Referer header to make sure that your parent is a trusted domain
Set targetOrigin to restrict recipients to those intended

Related

What are the security implications of uploading files from an iframe?

Suppose I have a drawing html application that my users can use in their web pages. They include the widget setting its src in an iframe (with their generated key passed as query string), I send it with a frame-ancestors header to restrict use to their domain and their users can use the widget to draw.
Now suppose they want to load drawings saved on their servers and pass them to my iframe widget, and they want users to click a button (on their site) to save the current drawing on their server. In both cases, they can send a message to my iframe specifying a signed url, and my iframe can listen to the event and use fetch to, respectively, download or upload the desidered asset.
What are the security implications of my iframe downloading or uploading on their behalf? Is this setup solid or can it be abused? If it can be abused, how?
I am not sure of downloading and uploading , but it is possible to share/pass messages to and from iframe.
More details here - https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
Security concerns
If you do not expect to receive messages from other sites, do not add any event listeners for message events. This is a completely foolproof way to avoid security problems.
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.
Always specify an exact target origin, not *, when you use postMessage to send data to other windows. A malicious site can change the location of the window without your knowledge, and therefore it can intercept the data sent using postMessage.

Why is using '*' as the targetOrigin for postMessage a security risk?

I'm having a hard time understanding the security issues when using a wildcard for the targetOrigin of the postMessage() method. Doesn't the window you call postMessage() on already have an origin that we are sending data to? How would someone be able to interfere with that? Would it be bad to set the targetOrigin to the window's origin using window.location.origin?
I understand the importance of checking the event origin on the receiving end (as illustrated here), but I can't seem to wrap my head around why it is bad for the sending end to use the wildcard as the targetOrigin when the window already has a specific origin.
It isn't a risk per se. It just means that anybody can embed your content in a frame and read the messages you send over the API. If the information is safe to trust anyone with, then that is fine. If it is data that should be kept private between your site, your visitor's and specific partner sites then you should be more cautious about whom you trust with the contents of the message.
Explicitly giving permission to whatever origin the request comes from is effectively the same as using '*'. You should filter on a whitelist of origins if the data needs to be kept private.

Why will disabling Browser Web Security (e.g. Chrome) help doing Cross-Site-Requests?

We have several internal web applications. One of those needs to access all the other applications. Problem is: Same-Orign-Policy.
Actually I did manage to get around it. First of all, the IE is quite sloppy what concerns web security. So, it actually asked me whether I want to have these requests done or not. If I clicked yes, he just executed the cross site requests.
But since most of the users won't use IE, there was the need to make it run in another browser.
So, I tried to make it run in Google Chrome. And after some research I found out, that it will work when I turn of the Web Security by using the execution parameter --disable-web-security.
This did the job. But unfortunately, most of the users won't be using this execution parameter. Therefore I need another solution.
Then I came across CORS. CORS seems to be implemented in Chrome, but it has one drawback (for me). I need to set headers on the server side.
For reasons I won't discuss in here, this is a no go.
So what I was actually wondering about is:
Why will disabling Browser's Web Security do the job, while I need the server to allow the request when using CORS?
What exactly happens inside the browser when I disable the web security?
And is there another way to execute my CSR without adding headers on the server's side or disabling the security?
Thanks in advance
EDIT: JSONP is out of question either
Why will disabling Browser's Web Security do the job, while I need the server to allow the request when using CORS?
The point of the Same Origin Policy is to prevent Mallory's evil site from making Alice's browser go to Bob's site and expose Alice's data to Mallory.
Disabling security in the browser is, effectively, saying "I don't care about protecting my data on Bob's (or any other!) site". This is a dangerous thing to do if the browser is ever going to go near the open web. The option is provided to make development more convenient — I prefer a more controlled solution (such as the URL rewriting options in Charles proxy).
CORS is Bob's site saying "This URL doesn't contain any data that Mallory (or some other specific site, or everyone) shouldn't have access to, so they can access it. Bob's site can do this because it knows which parts of it contain public data and which parts contain private data.
What exactly happens inside the browser when I disable the web security?
It disables the aforementioned security feature and reduces the protection of the user's data.
And is there another way to execute my CSR without adding headers on the server's side or disabling the security?
A proxy. See Ways to circumvent the same-origin policy, specifically the Reverse Proxy method.
I guess you are using AJAX requests, here is another question Ways to circumvent the same-origin policy that has a big detailed answer.
You can use a Flash object (flash doesn't have this problem)
Also about "whats the worst could happen" http://blogs.msdn.com/b/ieinternals/archive/2009/08/28/explaining-same-origin-policy-part-1-deny-read.aspx and http://en.wikipedia.org/wiki/Cross-site_scripting

What's the point of the Anti-Cross-Domain policy?

Why did the creators of the HTML DOM and/or Javascript decide to disallow cross-domain requests?
I can see some very small security benefits of disallowing it but in the long run it seems to be an attempt at making Javascript injection attacks have less power. That is all moot anyway with JSONP, it just means that the javascript code is a tiny bit more difficult to make and you have to have server-side cooperation(though it could be your own server)
The actual cross-domain issue is huge. Suppose SuperBank.com internally sends a request to http://www.superbank.com/transfer?amount=100&to=123456 to transfer $10,000 to account number 123456. If I can get you to my website, and you are logged in at SuperBank, all I have to do is send an AJAX request to SuperBank.com to move thousands of dollars from your account to mine.
The reason JSON-P is acceptable is that it is pretty darn impossible for it to be abused. A website using JSON-P is pretty much declaring the data to be public information, since that format is too inconvenient to ever be used otherwise. But if it's unclear as to whether or not data is public information, the browser must assume that it is not.
When cross-domain scripting is allowed (or hacked by a clever Javascripter), a webpage can access data from another webpage. Example: joeblow.com could access your Gmail while you have mail.google.com open. joeblow.com could read your email, spam your contacts, spoof mail from you, delete your mail, or any number of bad things.
To clarify some of the ideas in the questions into a specific use case..
The cross domain policy is generally not there to protect you from yourself. Its to protect the users of your website from the other users of your website (XSS).
Imagine you had a website that allowed people to enter any text they want, including javascript. Some malicious user decides to add some javascript to the "about yourself" field. Users of your website would navigate his profile and have this script executed on their browser. This script, since its being executed on your website's behalf, has access to cookies and such from your website.
If the browser allowed for cross domain communication, this script could theoretically collect your info and then upload it to a server that the malicious user would own.
Here's a distinction for you: Cross-domain AJAX allows a malicious site to make your browser to things on its behalf, while JSON-P allows a malicious server to tamper with a single domain's pages (and to make the browser do things to that domain on your behalf) but (crucial bit) only if the page served went out of its way to load the malicious payload.
So yes, JSON-P has some security implications, but they are strictly opt-in on the part of the website using them. Allowing general cross-domain AJAX opens up a much larger can of worms.

Can one use Ajax on Google App Engine as a logged in user over https from a non-appspot.com domain?

Suppose:
You have a website http://www.example.com that redirects to a project on Google App Engine (i.e. example.appspot.com);
you want communications to pass between the user over SSL (i.e. https://example.appspot.com); and
You want the domain to be shown to the user to be *://www.example.com (i.e. not https://example.appspot.com).
Given that Google's Appspot HTTPS support only works for https://example.appspot.com (i.e. you cannot set up https://www.example.com with GAE), I'd like to have an Ajax solution, namely:
http://www.example.com serves HTML and Javascript over http
Ajax requests go over SSL to https://example.appspot.com
My question/concern is: How does one ensure that the users logged into http://www.example.com (by way of Google's users API) pass their authentication credentials over Ajax to https://example.appspot.com?
This seems to be a violation of the same origin policy (which may or may not be a concern for the Google Users API), so how would one know what user is logged in to example.com for the Ajax requests to example.appspot.com?
Thoughts, comments and input is quite appreciated.
Thank you.
Brian
There are ways to work around same-origin when both sites cooperate, e.g. see this post, but only trial-and-error will reveal which techniques do work for your specific requirements (it may depend on how strictly the user has set security safeguards in their browser, as well as on server-side implementations).
You can try using JSONP to get around the around that. However JSONP doesnt have very good error recovery like JSON does when doing XHR calls.
Wouldn't it be far simpler to use frames? Serve up a single full-size frameset from yourdomain.com containing content from https://yourapp.appspot.com/.
Note, though, that either solution has the problem that users see an unsecured site, not a secured one.
example.appspot.com does not share any cookies with example.com - it will be impossible for you to identify the user without making them sign-in on example.appspot.com as well.
you could, of course, completely ditch Google Authentication on example.appspot.com and implement your own scheme; you could append a signature and the username to the AJAX requests you create and verify that signature on your app-engine app. if the signature is valid, just accept the user that was passed in as the authenticated user and pretend he logged in.

Categories

Resources