There is no reason that this should not work as long as third party cookies are enabled in your browser.
HTML form POSTs can be used, or in the case that the forms are a multi-stage process then this will be more useful to run as XHR requests as your attacking page can then control the requests and issue them in turn - just as your are doing.
Make sure that you are setting
withCredentials on your AJAX requests.
In jQuery this is done like the following
Other answers suggest that using
withCredentials means that a CORS pre-flight request is sent to the resource instead of the intended GET or POST. This is not the case as long as the request is a "simple request". If your exploit worked with HTML forms then the correct AJAX equivalent would be a simple request, so check that all you code is correct.
(note the following quote is from the original linked page to
CORS above http://www.html5rocks.com/en/tutorials/cors/, however, this is now a 404, therefore, the above link has been changed to here.)
Cross-origin requests come in two flavors:
- simple requests
- "not-so-simple requests" (a term I just made up)
Simple requests are requests that meet the following criteria:
- HTTP Method matches (case-sensitive) one of:
Simple requests are characterized as such because they can already be made from a browser without using CORS.
This is actually mentioned in the CORS specification and indicates that CORS does not actually add security, it only enables cross-domain communication when both the client and server opt into the specification. If both parties do not opt in (such as in a CSRF attack where the victim site does not wish to be communicated to in this fashion), then the browser will act in a similar way to pre-CORS. i.e. cookies will be sent although the response will not be readable:
resources conforming to this specification must always be prepared to expect simple cross-origin requests with credentials. Because of this, resources for which simple requests have significance other than retrieval must protect themselves from Cross-Site Request Forgery (CSRF) by requiring the inclusion of an unguessable token in the explicitly provided content of the request.
Back to your question:
I compared the actual HTTP requests for both content and order - all of the application layer data matches.
I suggest that you use an intercepting proxy such as Burp or Fiddler2 to verify the requests. Checking the requests from inside the browser is not an accurate way of verifying this because the requests viewed in Chrome are subject to be interpreted from the Origin of the page they are issued from and if the Origin doesn't see the response due to the Same Origin Policy, then neither will you in dev tools. Chrome informs you of this via the
“CAUTION: provisional headers are shown” message.
For example, the following is the same request as shown in Chrome dev tools and then in Burp. Notice how only the external tool shows the cookies.
I've tested this behaviour with Chrome 38, Firefox 32 and Internet Explorer 11 on Windows 7 x64, and it is consistent across browsers (however, make sure 3rd party cookies are enabled in settings) so this is further indication that this behaviour complies to current standards.
So my advice is to double check your code and requests using an intercepting proxy. Maybe post them on here for another pair of eyes to check as if it is working one way but not the other then there must be a mistake somewhere because the requests will not be the same.
Also, make sure that your code isn't exiting early due to the error returned because of Same Origin Policy violation.
Important note: A point was just made in this comment. Sometimes it may also be possible to trigger a simple request with the following Content-Type:
text/plain; application/json. Therefore if
application/json is checked for in server-side code, then these checks must be robust enough to ensure it is only this content type, or else another more robust method of anti-CSRF checking must be employed (e.g. un-guessable, session specific tokens within the POST body or header).