97

I am building a web service that exclusively uses JSON for its request and response content (i.e., no form encoded payloads).

Is a web service vulnerable to CSRF attack if the following are true?

  1. Any POST request without a top-level JSON object, e.g., {"foo":"bar"}, will be rejected with a 400. For example, a POST request with the content 42 would be thus rejected.

  2. Any POST request with a content-type other than application/json will be rejected with a 400. For example, a POST request with content-type application/x-www-form-urlencoded would be thus rejected.

  3. All GET requests will be Safe, and thus not modify any server-side data.

  4. Clients are authenticated via a session cookie, which the web service gives them after they provide a correct username/password pair via a POST with JSON data, e.g. {"username":"user@example.com", "password":"my password"}.

Ancillary question: Are PUT and DELETE requests ever vulnerable to CSRF? I ask because it seems that most (all?) browsers disallow these methods in HTML forms.

EDIT: Added item #4.

EDIT: Lots of good comments and answers so far, but no one has offered a specific CSRF attack to which this web service is vulnerable.

djsmith
  • 3,007
  • 3
  • 24
  • 21
  • tokenize your requests via session&cookie paired values, sanitize whatever directives you are triggering via the the submitted JSON, add salt for extra flavor – Brandt Solovij Jun 13 '12 at 05:09
  • I don't think there's enough info here to provide a good answer. What method of authentication are you using? Who are the intended consumers of the web service (ie, users of a site on the same host as your service?) – McGarnagle Jun 13 '12 at 05:39
  • 1
    All your current validations are perfectly sensible and do limit your attack-surface, but they don't actually address anything to do with what the CSRF vulnerability is. – Cheekysoft Jun 13 '12 at 10:54
  • possible duplicate of [CSRF - Can forged POSTs contain arbitrary data?](http://stackoverflow.com/questions/10788538/csrf-can-forged-posts-contain-arbitrary-data) – Gumbo Jun 13 '12 at 22:09
  • 3
    See http://security.stackexchange.com/questions/10227/csrf-with-json-post – eskatos Oct 06 '14 at 17:15
  • "Are PUT and DELETE requests ever vulnerable to CSRF?" In general yes. A JavaScript could create a PUT or DELETE request of (almost) any form. – David Balažic May 18 '15 at 13:38
  • 3
    @DavidBalažic What vector? If you're talking about AJAX, same-origin policies will prevent that. – djsmith May 19 '15 at 14:16

5 Answers5

82

Forging arbitrary CSRF requests with arbitrary media types is effectively only possible with XHR, because a form’s method is limited to GET and POST and a form’s POST message body is also limited to the three formats application/x-www-form-urlencoded, multipart/form-data, and text/plain. However, with the form data encoding text/plain it is still possible to forge requests containing valid JSON data.

So the only threat comes from XHR-based CSRF attacks. And those will only be successful if they are from the same origin, so basically from your own site somehow (e. g. XSS). Be careful not to mistake disabling CORS (i.e. not setting Access-Control-Allow-Origin: *) as a protection. CORS simply prevents clients from reading the response. The whole request is still sent and processed by the server.

maletor
  • 7,072
  • 7
  • 42
  • 63
Gumbo
  • 643,351
  • 109
  • 780
  • 844
  • 9
    As I commented on your linked answer, I assert that text/plain can indeed be used for JSON forgery if the server doesn't require application/json, using techniques similar to http://pentestmonkey.net/blog/csrf-xml-post-request. –  Jun 02 '13 at 20:54
  • 8
    That answer is correct until today, but will probably be wrong soon. W3C is considering adding enctype="application/json" to the HTML standard: http://darobin.github.io/formic/specs/json/ So don't rely on the type of the POST body for lasting security, use a anti-CSRF token. – LordOfThePigs Jul 11 '14 at 10:52
  • @LordOfThePigs Forging valid JSON is already possible with *text/plain*. – Gumbo Jul 11 '14 at 16:11
  • @Gumbo correct, but you currently can't set the enctype to `application/json` which is what is used to keep CSRF attacks at bay in this answer. The proposed standard will allow you to set enctype to `application/json`, which would defeat the content type checks outlined in the answer and open up the application to CSRF. – LordOfThePigs Jul 11 '14 at 19:54
  • 11
    It looks like the draft pre-empts this attack. Section 5 specifies that `application/json` form posts must conform to the same origin policy, meaning the attack is no stronger than XHR. – James_pic Mar 22 '15 at 11:08
  • So only POST and PUT benefit from the JSON content type? Do I have to use CSRF tokens to protect GET and DELETE in a REST API? I'm planning to use HttpOnly session IDs. – Joe Lapp Jun 12 '16 at 23:32
  • Until Chrome 59 you could use navigator.sendBeacon to POST JSON, cross domain. – Maciej Krawczyk Jul 11 '17 at 05:04
  • as an extra layer of protection for CSRF, you can mark your session cookies with SameSite=Strict (or "Lax"). Very easy to add on server, and no change needed on client. But currently (2018) supported by only 70% of browsers used on internet – arcuri82 Oct 22 '18 at 09:33
3

Yes, it is possible. You can setup an attacker server which will send back a 307 redirect to the target server to the victim machine. You need to use flash to send the POST instead of using Form.

Reference: https://bugzilla.mozilla.org/show_bug.cgi?id=1436241

It also works on Chrome.

Timothy Leung
  • 1,407
  • 7
  • 22
  • 39
0

It is possible to do CSRF on JSON based Restful services using Ajax. I tested this on an application (using both Chrome and Firefox). You have to change the contentType to text/plain and the dataType to JSON in order to avaoid a preflight request. Then you can send the request, but in order to send sessiondata, you need to set the withCredentials flag in your ajax request. I discuss this in more detail here (references are included):

http://wsecblog.blogspot.be/2016/03/csrf-with-json-post-via-ajax.html

  • 1
    That is unnecessary. If server reads plaintext requests as JSON, a form encoded as plaintext is enough to forge such request, as Gumbo has mentioned. API servers should simply reject plaintext requests. – Franklin Yu Mar 07 '18 at 22:38
-1

I have some doubts concerning point 3. Although it can be considered safe as it does not alter the data on the server side, the data can still be read, and the risk is that they can be stolen.

http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx/

panteo
  • 720
  • 8
  • 12
  • 1
    That only works if the top level object returned by the API is a JSON array, since Javascript allows overriding the Array constructor. A top level object is safe. More at http://flask.pocoo.org/docs/0.10/security/#json-security. – btubbs May 07 '15 at 02:46
  • According to the author himself, “*I don't think any modern browsers have this flaw anymore*”. – Franklin Yu Mar 07 '18 at 22:35
-8

Is a web service vulnerable to CSRF attack if the following are true?

Yes. It's still HTTP.

Are PUT and DELETE requests ever vulnerable to CSRF?

Yes

it seems that most (all?) browsers disallow these methods in HTML forms

Do you think that a browser is the only way to make an HTTP request?

symcbean
  • 47,736
  • 6
  • 59
  • 94
  • 4
    Just because a service uses HTTP does not make it vulnerable to CSRF. Can you identify an actual CSRF attack vector to which this service, as described, is vulnerable? And of course I don't think a browser is the only way to make an HTTP request, but the browser it the most common (only?) for a user to be tricked into making a forged, cross-site request that they did not expect. – djsmith Jun 13 '12 at 12:34
  • In other words, show me a specific CSRF attack vector that uses PUT to trick a user into submitting a PUT request to my web service (as described). I believe it is not possible. – djsmith Jun 13 '12 at 13:11
  • @symcbean: Could you please either post references or otherwise defend your answer? I've not voted on this answer, I'd like you to chime in first. Thanks. – dotancohen Mar 02 '13 at 15:15
  • Is Google down again? Leaving aside the content-type thing, old versions of Flash (more recent versions of flash have a cross domian control model - but it's different from HTML5's) - how about jar smuggling - http://pseudo-flaw.net/content/web-browsers/corrupted-jars/ (Java executes in active context but can invoke javascript in passive context). Then there's DNS rebinding attacks and MITM attacks – symcbean Dec 04 '13 at 22:49
  • Browser plugins can read your CSRF cookie and send any header they want, so even the defacto standard CSRF enforcement mechanisms are vulnerable to a malicious browser plugin. – djsmith Dec 06 '13 at 15:00
  • @djsmith: No: the window of opportunity with token based mechanisms is MASSIVELY reduced for plugin, SSLStrip and MITM attacks. (And, BTW for those who downvoted my answer, bypassing pre-flight is easy by setting the content type to text/plain - djsmith added the content type constraint after my answer). – symcbean Dec 06 '13 at 19:36
  • This answer is lazy, and dangerously lacking details or recommendations. But, on a very high level this is 100% not-wrong. – AJB Dec 07 '15 at 11:16
  • HTTP is ever-evolving; yesterday's carefree techniques are tomorrows death-traps. – AJB Dec 07 '15 at 11:17
  • If you override your request methods on the server-side, `PUT` is no different than `POST`. – AJB Dec 07 '15 at 11:18
  • HTTP is not limited to popular web browsers, and the so-called `IOT` is going to throw even more complexity onto this fire. – AJB Dec 07 '15 at 11:19