38

I am playing around with a test application which accepts JSON requests and response is also JSON. I am trying to do a CSRF for a transaction which accepts only JSON data with POST method in request. Application throws an error if URL is requested using get method (e.g. in <script src=).

Also for the attack to be meaningful i.e. transaction to go through, I have to send the data in the request. If I create my own page and send the JSON requests, cookies do not travel and hence server returning an unauthenticated error message.

There are no random tokens in original request by server.

I was wondering is there any way to carry out a successful CSRF attack in this scenario.

Sachin Kumar
  • 820
  • 3
  • 9
  • 14

2 Answers2

43

You must at the very least check for Content-Type: application/json on the request.

It's not possible to get a POSTed <form> to submit a request with Content-Type: application/json. But you can submit a form with a valid JSON structure in the body as enctype="text/plain".

It's not possible to do a cross-origin (CORS) XMLHttpRequest POST with Content-Type: application/json against a non-cross-origin-aware server because this will cause a ‘pre-flighting’ HTTP OPTIONS request to approve it first. But you can send a cross-origin XMLHttpRequest POST withCredentials if it is text/plain.

So even with application/json checking, you can get pretty close to XSRF, if not completely there. And the behaviours you're relying on to make that secure are somewhat obscure, and still in Working Draft stage; they are not hard-and-fast guarantees for the future of the web.

These might break, for example if a new JSON enctype were added to forms in a future HTML version. (WHATWG added the text/plain enctype to HTML5 and originally tried also to add text/xml, so it is not out of the question that this might happen.) You increase the risk of compromise from smaller, subtler browser and plugin bugs in CORS implementation.

So whilst you can probably get away with it for now, I absolutely wouldn't recommend going forward without a proper anti-XSRF token system.

bobince
  • 12,494
  • 1
  • 26
  • 42
  • 2
    It's good to add that the CSRF attacks will be blind (i.e. attacker won't get access to the response). – Krzysztof Kotowicz Dec 30 '11 at 12:27
  • 4
    +1 I would also say that relying upon any http header is a weaker form of protection because of HTTP Request Splitting (as in CRLF injection in the client). Using a token is still the recommended method of defense for most applications. – rook Dec 30 '11 at 16:22
  • Thanks bobince ... application rejects any request which is not application/json so for now I think I can't actually do a successful CSRF on this – Sachin Kumar Dec 30 '11 at 17:55
  • 9
    W3C HTML JSON form submission was published. http://www.w3.org/TR/html-json-forms/ – masakielastic Jun 09 '14 at 16:51
  • 3
    A little update to this - it is possible now to send the application/json POSTs cross domain with navigator.sendBeacon API - https://developer.mozilla.org/en-US/docs/Web/API/Navigator/sendBeacon – Krzysztof Kotowicz Jun 05 '15 at 13:01
  • @KrzysztofKotowicz: The [specification](http://www.w3.org/TR/beacon/) indicates that the browser should use CORS for this request, so this should not be an attack vector in this scenario. (That said, it looks like a Mozilla bug did lead to a [vulnerability](http://www.cvedetails.com/cve/CVE-2014-8638/).) – Kevin Christopher Henry Jun 23 '15 at 01:43
  • Unfortunately .sendBeacon() sends text/plain; charset=UTF-8, so no luck here either (Chrome 44). – kravietz Sep 04 '15 at 09:50
  • 1
    @kravietz You've done something wrong. Chrome 57 either re-introduced this bug or it was never fixed because I've managed to just exploit using exactly this. Use something like this: `var blob= new Blob([JSON.stringify(YOUR JSON)], {type : 'application/json; charset=UTF-8'});` to generate a JSON blob and it'll send perfectly. CSRF in seconds! – Allison Apr 21 '17 at 04:21
  • @masakielastic Is the spec dead? Any actual browser implementation? – Franklin Yu Aug 09 '18 at 21:06
  • Could someone provide an update on this ? Is there any work or RFC ongoing that address this question? – iwaduarte Mar 29 '21 at 16:36
7

This is exploitable using Flash, according to https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_Flash

The ability to make cookie-bearing cross-domain HTTP GET and POST requests via the browser stack, with fewer constraints than typically seen elsewhere in browsers. This is achieved through the URLRequest API. The functionality, most notably, includes the ability to specify arbitrary Content-Type values, and to send binary payloads.

I haven't tested it myself but it sounds plausible.

Update: It looks like the latest Flash releases no longer allow any cross-domain requests by default, rendering this unexploitable.

Update #2: however there's a longstanding vulnerability in flash's handling of 307 redirects which means this is still exploitable

albinowax
  • 91
  • 1
  • 5