Why do browser APIs restrict cross-domain requests?

10,827

Solution 1

If I visit a malicious website, I want to be sure that :

  1. It cannot read my personal data from other websites I use. Think attacker.com reading gmail.com
  2. It cannot perform actions on my behalf on other websites that I use. Think attacker.com transferring funds from my account on bank.com

Same Origin Policy solves the first problem. The second problem is called cross site request forgery, and cannot be solved with the cross-domain restrictions currently in place.

The same origin policy is in general consistent with the following rules -

  • Rule 1: Doesn't let you read anything from a different domain
  • Rule 2: Lets you write whatever you want to a different domain, but rule #1 will not allow you to read the response.
  • Rule 3: You can freely make cross-domain GET requests and POST requests, but you cannot control the HTTP headers

Lets see how the various things you have listed line up to the above rules :

  1. <img> tags let you make a HTTP request, but there is no way to read the contents of the image other than simply displaying it. For example, if I do this <img src="http://bank.com/get/latest/funds"/>, the request will go through (rule 2). But there is no way for the attacker to see my balance (rule 1).

  2. <script> tags work mostly like <img>. If you do something like <script src="http://bank.com/get/latest/funds">, the request will go through. The browser will also try to parse the response as JavaScript, and will fail.

  3. There is a well known abuse of <script> tags called JSONP, where you collude with the cross-domain server so that you can 'read' cross-domain. But without the explicit involvement of the cross-domain server, you cannot read the response via the <script> tag

  4. <link> for stylesheets work mostly like <script> tags, except the response is evaluated as CSS. In general, you cannot read the response - unless the response somehow happens to be well-formed CSS.

  5. <iframe> is essentially a new browser window. You cannot read the HTML of a cross-domain iframe. Incidentally, you can change the URL of a cross-domain iframe, but you cannot read the URL. Notice how it follows the two rules I mentioned above.

  6. XMLHttpRequest is the most versatile method to make HTTP requests. This is completely in the developers control; the browser does not do anything with the response. For example, in the case of <img>, <script> or <link>, the browser assumes a particular format and in general will validate it appropriately. But in XHR, there is no prescribed response format. So, browsers enforce the same origin policy and prevent you from reading the response unless the cross domain website explicitly allows you.

  7. Fonts via font-face are an anomaly. AFAIK, only Firefox requires the opt-in behavior; other browsers let you use fonts just like you would use images.

In short, the same origin policy is consistent. If you find a way to make a cross-domain request and read the response without explicit permission from the cross-domain website - you'll make headlines all over the world.

EDIT : Why can't I just get around all of this with a server-side proxy?

For gmail to show personalized data, it needs cookies from your browser. Some sites use HTTP basic authentication, in which the credentials are stored in the browser.

A server-side proxy cannot get access to either the cookies or the basic auth credentials. And so, even though it can make a request, the server will not return user specific data.

Solution 2

Consider this scenario...

  1. You go to my malicious website.
  2. My site makes an XHR to your banking website and requests the form for bank transfer.
  3. The XHR reads the token that prevents CSRF and POSTs the form alongside the security token and transfers a sum of money to my account.
  4. (I) Profit!!!

Without Same Origin Policy in existence, you could still POST that form, but you wouldn't be able to request the CSRF token that prevents CSRFs.

Server side code does not run on the client's computer.

Solution 3

The main issue with XHR is that they can not just send a request but you are also able to read the response. Sending almost arbitrary requests was already possible. But reading their responses was not. That’s why the original XHR did not allow any cross-origin requests at all.

Later, when the demand for cross-origin requests with XHR arose, the CORS was established to allow cross-origin requests under specific conditions. One condition is that particular request methods, request header fields, and requests that would contain user credentials require a so called preflight request with which the client can check whether the server would allow the request. With this the server has the ability to restrict access to only specific origins as otherwise any origin could send requests.

Share:
10,827
Domenic
Author by

Domenic

I'm a developer on the Google Chrome team, working to make the web platform more awesome. I work on web specs at the WHATWG, including editing the HTML Standard and Streams Standard. I help improve the JavaScript standard at Ecma TC39, representing Chrome's interest there and proposing some new features for future inclusion. Once upon a time I was elected to the W3C TAG to ponder issues of web architecture. In my spare time, my hobbyist programming centers around lots of Node.js and web apps. My favorite project is currently jsdom. I also used to present a lot at conferences. Check me out on GitHub and npm.

Updated on June 20, 2022

Comments

  • Domenic
    Domenic almost 2 years

    XMLHttpRequests require CORS to work cross-domain. Similarly for web fonts, WebGL textures, and a few other things. In general all new APIs seem to have this restriction.

    Why?

    It's so easy to circumvent: all it takes is a simple server-side proxy. In other words, server-side code isn't prohibited from doing cross-domain requests; why is client-side code? How does this give any security, to anyone?

    And it's so inconsistent: I can't XMLHttpRequest, but I can <script src> or <link rel> or <img src> or <iframe>. What does restricting XHR etc. even accomplish?

  • Sripathi Krishnan
    Sripathi Krishnan over 12 years
    Actually, no. Same origin policy prevents reading from other websites. It does not prevent writing to other websites. In general, none of the current browser security policies prevent CSRF.
  • user3167101
    user3167101 over 12 years
    @SripathiKrishnan I updated my post to hopefully make it a little clearer.
  • Sripathi Krishnan
    Sripathi Krishnan over 12 years
    Oops, sorry. I missed the 'requests a token' bit in your answer. I thought you meant to say same origin policy prevents CSRF.
  • Domenic
    Domenic over 12 years
    I don't really understand. Are you describing a phishing attack, or one in which the username/password is already compromised? In either case, it seems trivial to move all this work through a server-side proxy: why is running on the client's computer important?
  • Domenic
    Domenic over 12 years
    Right, I understand how CORS works, but why is being able to read a response dangerous?
  • Domenic
    Domenic over 12 years
    Hmm... I'm beginning to connect the dots. This is definitely the most helpful answer so far. But, could you expand on why client code issuing a GET request to gmail.com is worse than server code? I think I understand why but for this to be a complete answer it's important to address the "why can't I just get around all of this with a server-side proxy" question.
  • Gumbo
    Gumbo over 12 years
    Although it’s the document that initiates the request, it’s the user’s browser that actually sends the request. And the browser would send any credentials with it as if the user would have requested it directly. The response might contain sensitive information that should only be accessible to the user but that the initiating script can then access. That’s why the original XHR did not allow any cross-origin requests.
  • Gumbo
    Gumbo over 12 years
    But now the ‘extended’ XHR (formerly known as XHR level 2) does allow cross-origin requests when the rules of CORS are obeyed.
  • Sripathi Krishnan
    Sripathi Krishnan over 12 years
    @Domenic - See my updates. When client side code makes a request, the cookies get passed along implicitly. These cookies allow the cross-domain server to identify the user and therefore return personalized data. A server side proxy won't have access to these cookies, so it cannot read personal data.
  • Domenic
    Domenic over 12 years
    Excellent, thank you! It's especially helpful that you explicitly pointed out cookies and basic auth credentials; I had only thought of cookies.
  • user3167101
    user3167101 over 12 years
    @Domenic Nope. How can you proxy something that relies on the client's cookies?
  • Ruan Mendes
    Ruan Mendes over 10 years
    I think this is missing the fact that cross domain script tags don't send the cookies for the current site, so the attacker.com can't pretend they are you
  • Royi Namir
    Royi Namir almost 10 years
    #2 is not correct. old browser can overload the object SET in JS. this is why while(1) are all about
  • Rabbi
    Rabbi over 5 years
    So it's all about the cookies? Making sure that websites can't use cookies stored by a different website to make requests? Then why isn't that the only restriction? Why isn't CORS just a "Cookies Usage Policy"? Access-Control-Allow-Origin should change whether the cookies of the target site or the cookies of the origin site are used. Aside from that, all http should work like it would from a server or native code.