CSRF with JSON POST
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.
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