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.
Important note up front: If the server at the other end doesn't enable it, there's nothing you can do in your client-side code that will allow a cross-origin ajax request.
Let me give you a background before answering your question:
Simply put, same-origin security policy makes sure that scripts from one origin may not fetch content from other origins. Now to explain you the concept of origin, let me quote part of the Wikipedia article of Same-Origin Security Policy:
The following table gives an overview of typical outcomes for checks against the URL "http://www.example.com/dir/page.html".
Compared URL Outcome Reason
------------------------------------------------------- ------- ----------------------
http://www.example.com/dir/page2.html Success Same protocol and host
http://www.example.com/dir2/other.html Success Same protocol and host
http://username:[email protected]/dir2/other.html Success Same protocol and host
http://www.example.com:81/dir/other.html Failure Same protocol and host but different port
https://www.example.com/dir/other.html Failure Different protocol
http://en.example.com/dir/other.html Failure Different host
http://example.com/dir/other.html Failure Different host (exact match required)
http://v2.www.example.com/dir/other.html Failure Different host (exact match required)
http://www.example.com:80/dir/other.html Depends Port explicit. Depends on implementation in browser.
Unlike other browsers, Internet Explorer does not include the port in the calculation of the origin, using the Security Zone in its place.
So, for example, your JavaScript cannot download anything from (aka, make an HTTP request to) a web server other than the server it originated from. This is exactly why you cannot make XmlHttpRequests (aka AJAX) to other domains.
CORS is one way the server at the other end (not the client code in the browser) can relax the same-origin policy.
The CORS standard works by adding new HTTP headers which allow servers to serve resources to permitted origin domains. Browsers support these headers and respect the restrictions they establish.
Example: Say your site is http://my-cool-site.com
and, you have a third party API at domain http://third-party-site.com
, which you can access via AJAX.
And let's assume that a page from your server my-cool-site.com
made a request to third-party-site.com
. Normally, users browser will decline AJAX calls to any other site other than your own domain/subdomain per the Same-Origin Security Policy. But if the browser and the third party server supports CORS, following things happen:
Browser will send and Origin
HTTP header to third-party-site.com
Origin: http://my-cool-site.com
If the third party server accepts requests from your domain, it will respond with an Access-Control-Allow-Origin
HTTP header:
Access-Control-Allow-Origin: http://my-cool-site.com
To allow all domains, third party server can send this header:
Access-Control-Allow-Origin: *
If your site is not allowed, browser will throw an error.
If the client's have fairly modern browsers that support CORS, and your third party server supports CORS as well, CORS can be useful to you.
In some obsolete browsers (IE8, for instance), you have to use a Microsoft-specific XDomainRequest
object instead of XMLHttpRequest
to make a call that will work correctly with CORS; this outdated now, all modern browsers (including from Microsoft) handle CORS in XMLHttpRequest
instead. But if you need to support obsolete browsers, this page describes it:
To make a CORS request you simply use XMLHttpRequest
in Firefox 3.5+, Safari 4+ and Chrome and XDomainRequest
object in IE8+. When using XMLHttpRequest
object, if the browser sees that you are trying to make a cross-domain request it will seamlessly trigger CORS behaviour.
Here is a javascript function that helps you create a cross browser CORS object.
function createCORSRequest(method, url){
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr){
// XHR has 'withCredentials' property only if it supports CORS
xhr.open(method, url, true);
} else if (typeof XDomainRequest != "undefined"){ // if IE use XDR
xhr = new XDomainRequest();
xhr.open(method, url);
} else {
xhr = null;
}
return xhr;
}
Again, that's only necessary for obsolete browsers.
The above reasons are why you cannot use Amazon's web services from your script. And Amazon server will only allow downloading their JavaScript files to pages served from selected domains.
To answer your numbered questions:
- The file will be downloaded by the browser if it is in the same origin.
- If it is not in the same origin, the file will be downloaded if a CORS request succeeds.
- Or otherwise, downloading the script will fail.
- If the download succeeds, the content of the JavaScript file will be loaded to browser's memory, interpreted, and executed.
See description on CORS to understand.
Best Answer
The important thing to note here is that if the user is signed in to a site
http://example.com/
and the requesthttp://example.com/delete?id=1
deletes a post by the user, then the following code will delete the user's post: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 dohttp://example.com/delete?id=1&txid=SomethingTheUserCannotGuess
Now the following attack won't work:
...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 requesthttp://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:
...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, andhttp://attacker.com/
is the site of the attacker. Ifhttp://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, ifhttp://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:
...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:
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.