Given:
- Alice, a user with a browser
- Bob, a site owner with a website
- Mallory, a malicious site owner with a website
Alice has an account on Bob's server. Maybe it is her webmail. Maybe it is her online banking. Maybe it is somewhere she likes to shop.
Alice visits Mallory's website, not knowing that it is evil.
The Same Origin Policy prevents Mallory's website from using JavaScript to tell Alice's browser to make a request to Bob's website and give Alice's personal information (her bank balance for instance) to Mallory's website (and therefore to Mallory).
(Sometimes the request will be blocked because the conditions require a pre-flight request, other times the request will go through but the response will not be provided to Mallory's site. Look up CSRF if you want to defend against attacks where the danger lies in what the server does when it gets the request rather then in information leaking from the response).
CORS allows Bob to say that a resource on his website does not contain any personal information so that it is safe to allow other sites to access it (or that a particular site can be trusted with the personal information).
So as soon as somebody manages to inject a piece of JS code into a page,
XSS is a completely different security problem. You need to prevent people injecting JS.
The important thing to note here is that if the user is signed in to a site http://example.com/
and the request http://example.com/delete?id=1
deletes a post by the user, then the following code will delete the user's post:
<script src="http://example.com/delete?id=1" />
This is called a CSRF/XSRF attack (cross-site request forgery). This is why most server-side web applications demand a transaction ticket: instead of http://example.com/delete?id=1
you have to do http://example.com/delete?id=1&txid=SomethingTheUserCannotGuess
Now the following attack won't work:
<script src="http://example.com/delete?id=1" />
...because it doesn't contain the txid parameter. Now, let's consider what happens if the site could be accessed using XmlHttpRequest. The script running on the user's browser could behind the user's back retrieve and parse http://example.com/pageThatContainsDeleteLink
, extract the txid and then request http://example.com/delete?id=1&txid=SomethingTheUserCannotGuess
Now, if XmlHttpRequest cannot access sites having a different origin, the only way to try to retrieve the txid would be to try to do something like:
<script src="http://example.com/pageThatContainsDeleteLink" />
...but it doesn't help as the result is a HTML page, not a piece of JavaScript code. So, there's a reason why you can include <script>
s from other sites but not access other sites via XmlHttpRequest.
You may be interested in reading this: http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx/
This attack worked against Gmail back in the day and allowed you to fetch the user's mails from JavaScript code running on another site. This all shows that the security model of WWW is very subtle and not well thought of. It has evolved instead of being well-designed.
As for your question: you seem to think that the server http://example.com/
is the malicious one. That's not the case. Using the notations of my answer, http://example.com/
is the server that is the target of the attack, and http://attacker.com/
is the site of the attacker. If http://example.com/
opens up the possibility to send requests using JSONP or CORS, it is true that it may become vulnerable to the CSRF/XSRF attack I just described. But it does not mean that other sites would become vulnerable to the attack. Similarly, if http://attacker.com/
opens up the possibility to send requests using JSONP or CORS, the attacker's site just became vulnerable to a CSRF/XSRF attack. Thus, a misinformed server administrator may open up a hole in his own site but it doesn't affect the security of other sites.
Edit: a valid comment was made. It explained that the following code:
<script src="http://example.com/delete?id=1" />
...sends a GET request, and that example.com
should accept only POST or DELETE requests if the request changes state such as deletes something important.
This is true, a well-designed site shouldn't change state based on any GET request. However, this sends a POST request:
<p>You just won $100! Click below to redeem your prize:</p>
<form action="http://example.com/delete" method="post">
<input type="hidden" name="id" value="1" />
<input type="submit" value="Redeem prize" />
</form>
In this case, the code claiming the user won $100 can be embedded into the attacker's site and it sends a POST request not to the attacker's site but rather the victim's site.
Best Answer
The default behavior of web browsers that initiate requests from a page via JavaScript (AKA AJAX) is that they follow the same-origin policy. This means that requests can only be made via AJAX to the same domain (or sub domain). Requests to an entirely different domain will fail.
This restriction exists because requests made at other domains by your browser would carry along your cookies which often means you'd be logged in to the other site. So, without same-origin, any site could host JavaScript that called logout on stackoverflow.com for example, and it would log you out. Now imagine the complications when we talk about social networks, banking sites, etc.
So, all browsers simply restrict script-based network calls to their own domain to make it simple and safe.
There are some known work-arounds in place (such as JSONP which doesn't include cookies in the request), but these are not a permanent solution.
CORS allows these cross-domain requests to happen, but only when each side opts into CORS support.