21

I am struggling a bit with MDN's description of the same-origin policy.

They state that:

Cross-origin writes are typically allowed....

Cross-origin embedding is typically allowed....

Cross-origin reads are typically not allowed...

I understand the second bullet allows standard embedding of cross-origin content (say from CDN), into a site:

  • <script src="...">
  • <link rel="stylesheet" href="...">

But, what is meant by writes are allowed, reads are not allowed? Does "writes" refer to my site writing to another site, or the opposite direction? Same with "read", what direction are they talking about there? Some examples would be greatly appreciated.

Community
  • 1
  • 1
Magnus
  • 6,791
  • 8
  • 53
  • 84
  • Writes generally means HTTP requests. This means in either direction. – SLaks Jun 19 '18 at 16:37
  • 1
    A cross-origin write is something like a `
    ` post to a different domain. Those are allowed by the browser, and are the reason that browsers alone do not solve your CSRF problems.
    – Pointy Jun 19 '18 at 16:40
  • 1
    It's worth remembering that MDN is collaboratively edted by the community. I don't think I'd've used the word "writes" there. It generates more confusion than it alleviates. – T.J. Crowder Jun 19 '18 at 16:48
  • @Pointy Is it necessary to check for an unguessable `CSRF` token whenever reading form data sent from another domain then? EDIT: I guess that makes sense, to avoid reading from malicious source. I haven't actually implemented such communication, so not sure how it is done / if my question makes sense. – Magnus Jun 19 '18 at 17:37
  • A CSRF token can be an explicit part of a form, or it can be added to XHR request headers. Whatever it is, it should not be possible for a third-party domain to read page content from your site that exposes the token. Generally, some secured value is used, unique for each user session. – Pointy Jun 19 '18 at 20:47

2 Answers2

12

MDN gives examples of what it means by writes:

Examples are links, redirects and form submissions. Certain rarely used HTTP requests require preflight.

So for instance, my site at example.com can have this:

<form action="https://google.com/search" id="kittens-form" target="_blank">
<input type="hidden" name="q" value="kittens">
</form>

...and do this:

document.getElementById("kittens-form").submit();

Example on jsFiddle

(In that specific case, since I have target="_blank", I'd have to do it in response to a user action or I'd trip over the popup blocker. But if I don't open a new window, I can do it any time I like.)

Same with "read", what direction are they talking about there?

They're talking about code running in origin A reading information from origin B. So my malicious example.com site can't read from your bank's website without your bank specifically allowing it via CORS (this is so I can't steal information about your bank account, since you may have a valid banking session running...).

More in this question's answers: Same origin Policy and CORS (Cross-origin resource sharing)

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Thank you T.J. But, if I can write, can't I then also read? I mean, I could write my malicious script to the banks DOM, then when it is executed on their end my script sends me all the info I want? – Magnus Jun 19 '18 at 16:45
  • 2
    @Magnus - Sending information to a site doesn't make the site run *your* code. A site certainly *can* accept code to run from some random untrusted origin on the web, but presumably your bank's website does not. Or won't for long... ;-) – T.J. Crowder Jun 19 '18 at 16:47
  • Another follow-up: How is a link a write operation? With a , I read for example a stylesheet from CDN. Isn't that a read operation? – Magnus Jun 19 '18 at 16:48
  • 4
    @Magnus - "Link" means `...`; when referring to the `link` element, one would need to be more specific than just the word "link." But in both cases, information (the URL and potentially query string parameters) are sent to the target site, which can use them. So that's "writing" (in a **very** loose sense) information to the target site, which the target site can "read." – T.J. Crowder Jun 19 '18 at 16:50
  • Haha, yes, I suspect it wouldn't live for long then. It would only be executed if they somehow read user input using `innerHtml` or `eval` for example? Side question: I can't possibly write as much to other sites' DOM as I like? I would then be able to run around breaking sites, no? – Magnus Jun 19 '18 at 16:51
  • 3
    @Magnus - You're thinking of communication between windows in the browser. That isn't what MDN is talking about. It's talking about browser-hosted JavaScript code sending information to the **server** of the site. (And no, you can't modify the DOM of a document loaded from a different origin, in the browser, except in a fairly limited way if both documents use `document.domain`.) – T.J. Crowder Jun 19 '18 at 16:58
  • 1
    Ah, "write" is pretty terrible term to use here then, as you noted above. My immediate thought was that they meant I would be allowed to get a hold of another window object: `const newWin = window.open('https://www.google.com', 'windowName');`, then write to its DOM as I wanted. Which I know isn't possible, thus the confusion :) Thanks again. – Magnus Jun 19 '18 at 17:04
2

I finally made myself clear after having been struggling half a hour about this saying:

  • Cross-origin writes are typically allowed....
  • Cross-origin embedding is typically allowed....
  • Cross-origin reads are typically not allowed...

It classifies the same-origin problems into three types, but, depending on whether interacting with the server, I'd prefer to classify the same-origin policy into two types:

  1. reading the already loaded resource of originA from within originB in the browser
  2. requesting the remote resource of originA from within originB in the browser

The first corresponds the "Cross-origin reads" case of the above quotes and the second corresponds the "Cross-origin writes" and "Cross-origin embedding". (so yes, you get that both "writes" and "embedding" actually mean requesting resources from remote server instead of directly reading from local)

The first type is simple to handle: the browser definitely block it. So that a javascript snippet of websiteA cannot read the cookie set by websiteB - thus ensures the safety of our web accounts.

The second type is somewhat complex, there're quite a few cases requests being initiated from within one origin to another, for now as far as I can list:

  1. the <a href=... linking(writes) to a different site
  2. the <form action=... method="POST"> that posts(writes) to a different site
  3. the <link rel="stylesheet" href="…"> that loads CSS style from a different site and embeds it into the origin page
  4. the <img> tag that loads an image elsewhere and embeds it into the original page
  5. the <script> which loads javascript code snippet elsewhere and embeds it into the original page
  6. XMLHttpRequest AJAX request
  7. Web Fonts (for cross-domain font usage in @font-face within CSS)
  8. WebGL textures.
  9. Images/video frames drawn to a canvas using drawImage().
  10. CSS Shapes from images.

In which , the browser allows the 1-5 cases while blocks 6-10, there might be 11, 12, ... cases in the future that are blocked by browsers, this Mozilla page could be a better place to keep up with the new blocking cases in the future.


(initially post on: https://cifer76.github.io/posts/same-origin-policy/)

cifer
  • 615
  • 1
  • 9
  • 25