3

I am newbie to website security and currently trying to understand Same-Origin-Policy in some depth. While there are very good posts on stackoverflow and elsewhere about the concept of SOP, I could not find updated information on whether chrome and other browsers allow cross-domain XHR post requests to be 'sent' from the first place.

From this 5 year old post, it appears that chrome allows the request to pass through to the requested server but does not allow reading the response by the requester.

I tested that on my website trying to change user info on my server from a different domain. Details below:

  1. My domain: "www.mysite.com"
  2. Attacker domain: "www.attacker.mysite.com" According to Same-Origin-Policy those two are considered different Origins.
  3. User (while logged in to www.mysite.com) opens www.attacker.mysite.com and presses a button that fires a POST request to 'www.mysite.com' server...The submitted hidden form (without tokens in this case) has all the required information to change the user's info on 'www.mysite.com' server --> Result: CSRF successful attack: The user info does indeed change.

  4. Now do the same but with javascript submitting the form through JQuery .post instead of submitting the form--> Result: Besides chrome giving the normal response:

No 'Access-Control-Allow-Origin' header is present on the requested resource

, I found that no change is done on the server side...It seems that the request does not even pass through from the browser. The user info does not change at all! While that sounds good, I was expecting the opposite.

According to my understanding and the post linked above, for cross-domain requests, only the server response should be blocked by the browser not sending the post request to the server from the first place. Also, I do not have any CORS configuration set; no Access-Control-Allow-Origin headers are sent. But even if I had that set, that should apply only on 'reading' the server response not actually sending the request...right?

I thought of preflights, where a request is sent to check if it's allowed on the server or not, and thus blocking the request before sending its actual data to change the user info. However, according to Access_Control_CORS , those preflights are only sent in specific situations which do not apply to my simple AJAX post request (which includes a simple form with enctype by default application/x-www-form-urlencoded and no custom headers are sent).

So is it that chrome has changed its security specs to prevent the post request to a cross domain from the first place? or am I missing something here in my understanding to the same-origin-policy?

Either way, it would be helpful to know if there is a source for updated security measures implemented in different web browsers.

Community
  • 1
  • 1
Ahmad Khaled
  • 367
  • 2
  • 16

2 Answers2

5

The XMLHttpRequest object behavior has been revisited with time.

The first AJAX request were unconstrained.
When SOP was introduced the XMLHttpRequest was updated to restrict every cross-origin request

  1. If the origin of url is not same origin with the XMLHttpRequest origin the user agent should raise a SECURITY_ERR exception and terminate these steps.

From XMLHttpRequest Level 1, open method

The idea was that an AJAX request that couldn't read the response was useless and probably malicious, so they were forbidden.
So in general a cross-origin AJAX call would never make it to the server. This API is now called XMLHttpRequest Level 1.

It turned out that SOP was in general too strict, before CORS was developed, Microsoft started to supply (and tried to standardize) a new XMLHttpRequest2 API that would allow only some specific requests, stripped by any cookie and most headers.

The standardization failed and was merged back into the XMLHttpRequest API after the advent of CORS. The behavior of Microsoft API was mostly retained but more complex (read: potentially dangerous) requests were allowed upon specific allowance from the server (through the use of pre-flights).

A POST request with non simple headers or Content-Type is considered complex, so it requires a pre-flight.

Pre-flights are done with the OPTIONS method and doesn't contain any form information, as such no updates on the server are done.
When the pre-flight fails, the user-agent (the browser) terminate the AJAX request, preserving the XMLHttpRequest Level 1 behavior.


So in short: For XMLHttpRequest the SOP was stronger, deny any cross-origin operations despite the goals stated by the SOP principles. This was possible because at the time that didn't break anything.
CORS loosened the policy allowing "non harmful" requests by default and allowing the negotiation of the others.

Margaret Bloom
  • 33,863
  • 5
  • 53
  • 91
  • 1
    Thanks for the nice overview...would you consider sharing a resource from which you fetched such information? Always interesting to know the history behind how things got the way they became. – Ahmad Khaled Oct 25 '16 at 20:27
  • But if a POST request from a cross origin requester does get processed by the server (CORS not enabled), does not that count as harmful? The state of the server has been changed by a request that wasn't supposed to be able to do that. – Sнаđошƒаӽ May 10 '20 at 14:45
  • 1
    @Sнаđошƒаӽ Yes, that would be harmful but the point of SOP is to prevent any web site from *reading* any other one (since that would access data from authenticated sessions). What you are describing is a CSFR, this can be avoided with, for example, a form token. It is up to the web site to implement security policies but SOP was needed because a website cannot tell if a *read* request is legitimate or not. Note that POST requests responses cannot be read. See [this](https://security.stackexchange.com/questions/145013/when-does-the-same-origin-policy-prevent-a-request-from-being-sent) – Margaret Bloom May 10 '20 at 16:23
  • 1
    @Sнаđошƒаӽ As to, "Why allowing POSTs in the first place", well... I'm not sure. I believe it's because it is a design feature of HTTP, [the W3C kind of said something like that](https://security.stackexchange.com/questions/187511/why-are-cross-domain-post-requests-allowed). Probably, they strictly focused on the main issue: reading of third party website, and didn't want to prohib writing. – Margaret Bloom May 10 '20 at 16:31
2

OK...I got it...It's neither a new policy in chrome nor missing something in SOP... The session cookies of "www.mysite.com" were set to "HttpOnly" which means, as mentioned here, that they won't be sent along with AJAX requests, and thus the server won't change the user's details in point (4).

Once I added xhrFields: { withCredentials:true } to my post request, I was able to change the user's information in a cross-domain XHR POST call as expected.

Although this proves the already known fact that the browser actually sends the cross-domain post requests to the server and only blocks the server response, it might still be helpful to those trying to deepen their understanding to SOP and/or playing with CORS.

Community
  • 1
  • 1
Ahmad Khaled
  • 367
  • 2
  • 16