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

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.

Related

How is window.postMessage() "secure"?

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

postMessage target origin - window.parent.origin vs "*"

Is window.parent.postMessage(message, window.parent.origin) more secure than window.parent.postMessage(message, '*')?
We have an iframe component that is loaded by a parent frame. That frame can be from anywhere (our web application is a shared component and can be accessed from any client installation of our main product). So we can't know in advance who loaded us unless we keep some kind of database with allowed origins which we don't.
We are sending a postMessage() to our parent frame, and we can't know the target origin in advance, so I put '*'. I colleague of mine suggested I use window.parent.origin instead, but as far as I understand this has the same effect - postMessage will check that the target origin is the same as itself! Not to mention that it fails when cross-domain.
So am I missing something here? Does using window.parent.origin confer any greater security than a wildcard?
The wildcard "*" could be dangerous if parent page gets redirected to a malicious site that could receive your message with sensitive data.
In this particular case, the parent.origin wouldn't give any security benefits. Ideally, the component's server should be used to detect and the validate the origin of the parent window.
Is window.parent.postMessage(message, window.parent.origin) more secure than window.parent.postMessage(message, '*')?
It depends on what the danger is for you. And what do you consider safe use of your app.
Imagine that your iframe is hosted on domain A, and it is called from domain B. If in this case, sending messages from your iframe to the parent is considered dangerous, then yes - window.parent.postMessage(message, window.parent.origin) more secure than window.parent.postMessage(message, '*').
Using window.parent.origin as targetOrigin will not provide any data to the parent that hosted on a domain other than the iframe domain.

Is it possible to circumvent the same origin policy if you don't have control of the second origin?

This SO post lists numerous ways to circumvent this poilicy.
However, I can't tell if any of these are applicable to when you don't have access to the second origin.
Particularly this one, 3rd answer down, you insert a script that calls a script form the second origin.
<script src="http://..../someData.js?callback=some_func"/>
But in general do any of these methods allow circumvention when you are on origin one...and need access to origin two?
Yes, you can circumvent the Same Origin Policy without controlling the second server, but you can't do it without the cooperation of the owner of the second server. Often, as in your example, this is done by cooperating with the JSONP conventions. There is no other way of doing this without proxying the requests to the second server through the first.
Obviously this can't be possible, otherwise the policy would be useless. It's all about preventing you from pulling data from a third host, which is exactly what you are trying to do.
Note that browsers have no notion of what is part of the "private" local network and what is part of the "public" global internet. So this policy exists to prevent arbitrary Javascript code from accessing resources on your local network.
NO, that's the entire point. The SOP can be turned off only if the server specifically allows it thru either CORS or something like JSONP.
Inserting scriptlets is an attack (regardless of if your intentions are good). If I owned a domain and someone did that, they would be banned and reported to the authorities.
The closest you can come is to use server side proxy (i.e. have your js make requests your server, which in turn makes requests to the third party).

Is CORS a secure way to do cross-domain AJAX requests?

After reading about CORS (Cross-Origin Resource Sharing), I don't understand how it improves security. Cross-Domain AJAX communication is allowed if the correct ORIGIN header is sent. As an example, if I send
ORIGIN: http://example.com
The server checks if this domain is in the white list and, if it is, header:
Access-Control-Allow-Origin: [received url here]
is sent back, together with the response (This is the simple case, there are also prefighted requests, but the question is the same).
Is this really secure? If someone wants to receive the information, faking an ORIGIN headers seems like a really trivial task. Also the standard says that the policy is enforced in the browser, blocking the response if Access-Control-Allow-Origin is not correct. Obviously if anyone is trying to get that info, he will not use a standard browser to block it.
The purpose is to prevent this -
You go to website X
The author of website X has written an evil script which gets sent to your browser
that script running on your browser logs onto your bank website and does evil stuff and because it's running as you in your browser it has permission to do so.
The ideas is that your bank's website needs some way to tell your browser if scripts on website X should be trusted to access pages at your bank.
Just to add on #jcoder 's answer, the whole point of the Origin header isn’t to protect the resources requested on a server. That task is up to the server itself via other means exactly because an attacker is indeed able to spoof this header with the appropriate tools.
The point of the Origin header is to protect the user.
The scenario is the following:
an attacker creates a malicious website M
a user Alice is tricked to connect to M, which contains a script that tries to perform some actions through CORS on a server B that actually supports CORS
B will probably not have M in its Access-Control-Allow-Origin header, cause why would it?
The pivotal point is that M has no means to spoof or overwrite the Origin header, because the requests are initiated by Alice's browser. So her browser will set the (correct) Origin to M, which is not in the Access-Control-Allow-Origin of B, therefore the request will fail.
Alice could alter the Origin header herself, but why would she, since it would mean she is harming herself?
TL;DR: The Origin header protects the innocent user. It does not secure resources on a server. It is spoofable by an attacker on his own machine, but it cannot be spoofed on a machine not under his control.
Servers should still protect their resources, as a matching Origin header doesn't mean an authorized access. However, a Origin header that does NOT match means an unauthorized access.
You can't fake an Origin header with JavaScript in a web browser. CORS is designed to prevent that.
Outside of a web browser, it doesn't matter. It isn't designed to stop people from getting data that is available to the public. You can't expose it to the public without members of the public getting it.
It is designed so that given:
Alice, a person providing an API designed to be accessed via Ajax
Bob, a person with a web browser
Charlie, a third party running their own website
If Bob visits Charlie's website, then Charlie cannot send JS to Bob's browser so that it fetches data from Alice's website and sends it to Charlie.
The above situation becomes more important if Bob has a user account on Alice's website which allows him to do things like post comments, delete data, or see data that is not available to the general public — since without protection, Charlie's JS could tell Bob's browser to do that behind Bob's back (and then send the results to Charlie).
If you want to stop unauthorized people from seeing the data, then you need to protect it with passwords, SSL client certs or some other means of identity-based authentication/authorization.
The purpose of the same origin policy isn't to stop people from accessing website content generally; if somebody wants to do that, they don't even need a browser. The point is to stop client scripts accessing content on another domain without the necessary access rights. See the Wikipedia entry for Same Origin Policy.
"After reading about CORS, I don't understand how it improves security."
CORS does not improve security. CORS provides a mechanism for servers to tell browsers how they should be accessed by foreign domains, and it tries to do so in a way that is consistent with the browser security model that existed before CORS (namely the Same Origin Policy).
But the Same Origin Policy and CORS have a limited scope. Specifically, the CORS specification itself has no mechanism for rejecting requests. It can use headers to tell the browser not to let a page from a foreign domain read a response. And, in the case of preflight requests, it can ask the browser not to send it certain requests from a foreign domain. But CORS doesn't specify any means for the server to reject (that is, not execute) an actual request.
Let's take an example. A user is logged in to site A via a cookie. The user loads malicious site M, which tries to submit a form that does a POST to A. What will happen? Well, with or without CORS, and with or without M being an allowed domain, the browser will send the request to A with the user's authorization cookie, and the server will execute the malicious POST as if the user initiated it.
This attack is called Cross-Site Request Forgery, and CORS itself does nothing to mitigate it. That's why CSRF protections are so important if you allow requests to change data on behalf of users.
Now, the use of the Origin header can be an important part of your CSRF protection. Indeed, checking it is part of the current recommendation for multi-pronged CSRF defense. But that use of the Origin header falls outside the CORS specification.
In sum, CORS is a useful specification for extending the existing Same Origin Policy security model to other accepted domains. It doesn't add security, and sites need the same kinds of defense mechanisms that they did before CORS.
I am late to answer but I don't think any post here really provides the sought answer. The biggest takeaway should be that the browser is the agent that is writing the origin header value. An evil script cannot write the origin header value. When the server responds back with a Access-Control-Allow-Origin header, the browser tries to ensure that this header contains the origin value sent earlier. If not, it triggers an error and does not return the value back to the requesting script. The other answers to this question present a good scenario to when you would like to deny an answer back to the evil script.
#daniel f also provides a good answer to the question

Meaning of SOP (same origin policy)

What is the real meaning of SOP (Same Origin Policy)?
I know it means that the Javascript code from one origin cannot accuess resources from another origin. But what exactly does the word "resources" mean? For example:
Javascript code can access IMAGES from another site.
Javascript code cannot make ajax request to another side.
But when you use JSON padding, after completing the loading of a padded script tag, the 3rd party script will call your specified callback -- Javascript code from one site is invoking a method of Javascript code from another. Does this violate SOP?
There are several types but if we don't specify:
SOP refers to a mechanism that governs the ability for JavaScript and other scripting languages to access DOM properties and methods across domains
Here you have an excellent description of different types of SOP.
Same Origin Policy is mainly intended to prevent scripts for other domains to perform AJAX (XMLHTTP) requests in the context of the loaded domain and also restricts sites of other domain to access sites resources like cookies, local storage etc. It is more like a standard specification formulated for security measures and every browser has its own way of implementing it by adhering to specifications.
By saying 'prevent scripts for other domains to perform AJAX (XMLHTTP) requests' I mean the cross-origin requests which don't belong to the same domain.
For example, domain.com and test.domain.com belong to the same domain and the test is subdomain, while test.domain2.com belongs to an entirely different domain.
Now let us consider its security implications:-
1.Let us say a website site1.com has an API call to update the password. When the user inputs the required data an HTTP call is made to the backend and the user's authenticity is validated with the session data contained in cookies.
2)Now with this being said, if the attacker creates a site named site2 and has a javascript code to make an HTTP call to site1's change password endpoint. By browsers default behavior it attaches all the cookie data it has for site1 to the request which makes the HTTP call successful thus allowing attackers to succeed.
3)To be able to mitigate this browsers implemented SOP, which dictates the browsers javascript engine to block any request to cross domains like from site2 to site1 for example, unless instructed to allow to do so.
4)Now in this growing modern world with microservice architectures and multiple subdomains, this will be very problematic. To get around this browsers support cross-origin requests if the API response says so with headers like Access-Control-Allow-Origin, Access-Control-Allow-Methods, Access-Control-Allow-Credentials, etc.
5)To put it forward when the ajax request is made from site2 to site1, the browsers check the API response headers and allows the request if any of these values are present in response:-
Access-Control-Allow-Origin:* or Access-Control-Allow-Origin:site2.com or Access-Control-Allow-Origin:*.site2.com (wildcard entry)
6)With this being said there is a major loophole here, even if the sop policy blocks the request, it actually means that the browser blocks the site2 access to read the response data meaning the request was already made to the server. This scenario is only applicable to a few requests on specific conditions which doesn't trigger pre-flight options call. When the options call is made the browser will not allow the request to go through based on the header response in options call.
7)Now comes the second part to it which is Access-Control-Allow-Credentials. In the server response for options call, if the server sets the header to true all the confidential session data like Authorization header, secure cookies will be added to the cross-origin requests from site2 to site1.
Note:- This header is only added if Access-Control-Allow-Origin is very specific to a domain meaning it will not work for * value in the header. Is the Access-Control-Allow-Origin header is * then browsers SOP policy will kick in and blocks it from allowing the secure data if Access-Control-Allow-Credentials is set to true.
The SOP origin policy doesn't deal with image sources and external script includes. To be able to utilize control over those go through the Content Security Policy (CSP). Using it you could control access to external sites wrt to images, scripts, fonts, styles, etc. You would also be able to block unsafe-inline eval's in site like alert boxes to prevent some XSS attacks. This is new defacto standard and a lot of websites started implementing it.
To be able to prevent such attacks (CSRF attacks), websites also implement a csrf-token along with a form that changes on every state change. Even if attacker somehow makes the request from site2 to site1, the request will not go through as the server at site1 validates the csrf token along with the request, which the attacker cannot access through.
Other measures would add origin-based validation if the origin header is present.
JSONP is designed to allow such a mechanism through callbacks.
Sorry for such a long answer and the topic is far bigger than this. This is just my own understanding of it and let me know if I am wrong anywhere.
JSONP gets around the Same Origin Policy by dynamically adding a script tag to the DOM and calling a predefined function with the remote web service's JSON data as the parameter. The tag is not subject to the same origin policy and therefore can request content cross-domain.
Just like how you can use Google's version of jQuery on your site without violating SOP, you can "include" a script tag that calls a predefined function on the data you receive back from a web service.

Categories

Resources