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

  • GET/OPTIONS Requests are Rejected
  • Token is used for Authentication, Without token we cant access the application
  • Access-Control-Allow-Origin: * is set

I am building a web service that exclusively uses JSON for its request and response content

  • I'll go out on a limb here and say "yes": if you don't have GET or HTML in play, you can't have CSRF. – dandavis Nov 9 '17 at 5:20
  • @PortSwigger Bearer token. But would like to know what happens for both case – Mohammed Farhan Nov 13 '17 at 7:52
  • As the old comment seems to be deleted, could you elaborate what you mean by "both cases"? – Tom K. Nov 23 '17 at 10:39
  • Token based authentication or Session based authentication – Mohammed Farhan Nov 23 '17 at 12:43

This is not vulnerable if the content type only accepts application/json because you cant create an html form that posts that content type, and thats what you would need to do csrf if you cant use ajax, which you cant with the above CORS header. Also, if the token is in the authorization header, its not vulnerable because it wont be submitted in a csrf attack.

  • can xss attacks take place? – Mohammed Farhan Nov 13 '17 at 7:55
  • If content type is application/ json and its an api, then no xss can take place. If the response is embedded in a UI, then Xss attacks can take place if the response isnt being encoded before being processed. – joe Nov 13 '17 at 17:11

Your Access-Control-Allow-Origin would be checked with an OPTIONS request, which is rejected, so XHR is not possible.

In general, joe's answer is correct, but be aware that it's crucial to have the request content-type being checked by the web service to be application/json. Because it is indeed possible to send valid JSON data via form by leveraging the enctype="text/plain" attribute.

This works with Chrome (as far as I know it's up to the browser how to handle the text/plain content type):

<form action="https://example.com" method="post" enctype="text/plain">
    <input type="hidden" name='{"foo": "bar", "ignored-by-backend":"' value='"}'>

The browser will concatenate name and value separated by a = character. The JSON data sent to the web service looks like this:

{"foo": "bar", "ignored-by-backend":"="}

Also notice that there is a draft for allowing enctype="application/json", however it's not maintained anymore and as far as I know no browser currently implements it. But we cannot know if it will be possible some day.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.