10

I have a web service that takes POST data (JSON) and returns part of the request object in the JSON response.

This is open to XSS if the response is rendered as HTML by the browser since someone could add arbitrary HTML to the request object.

What is the standard way to mitigate this? Current options I can think of are:

  • Only allow requests with X-Requested-With: XMLHttpRequest header to stop attacks that rely on non-ajax requests to my service
  • Send the response with content type application/json and hope the browser refuses to render this as HTML
  • Encode unsafe characters in the response (how do I do this? using \uxxxx?)

I have been unable to find a concrete reference on this.

Flash
  • 201
  • 1
  • 2
  • 4

3 Answers3

5

Encode unsafe characters in the response (how do I do this? using \uxxxx?)

Yes. < to \u003C in particular.

There may be an option in your JSON encoder to do this already (eg in PHP, JSON_HEX_TAG); otherwise, it's a simple job to do a string replace after the encoding. (This is safe as there is no place a < may legally be used in JSON other than in a string literal.) At this point you can also include the leading chaff to prevent cross-origin script inclusion.

I would send as application/json as a matter of correctness, but I wouldn't trust every older browser to necessarily honour it. Relying on the X-Requested-With header is generally problematic as it doesn't play well with caching, though that may not be a concern for you.

bobince
  • 12,494
  • 1
  • 26
  • 42
  • 1
    As noted by Erlend, if you're going to use `Content-Type: application/json` as a security measure, then it makes sense to serve `X-Content-Type-Options: nosniff` as well, since this will protect IE 8 and 9 users against the MIME sniffing exploit I describe [in the second half of this answer](http://stackoverflow.com/a/21211222/1709587). (Of course, if you're already HTML-encoding all `<` characters then this is redundant, as is the `application/json` header itself from a security perspective.) – Mark Amery Jan 19 '14 at 12:05
4

The following points should be kept in mind

  • The potential XSS vulnerability can be avoided by using the correct Content-Type. All JSON responses should use the application/json type.

  • The nosniff header is used to disable content-sniffing on old versions of Internet Explorer.

  • Always have the outside primitive be an object for JSON strings:

Exploitable:

[{"object": "inside an array"}]

Not exploitable:

{"object": "not inside an array"}

Also not exploitable:

{"result": [{"object": "inside an array"}]}
Mohammed Farhan
  • 331
  • 2
  • 11
2

Set the Content-Type to application/json, and set X-Content-Type-Options: nosniff (the last header instructs the browser to use the given content-type - no extra guessing). You could even consider adding a Content-Disposition: attachment header. This will be ignored by XHR requests, but cause the download dialog to pop if an attacker tries to trick a user into opening it directly in the browser.

You could also have a look at: http://erlend.oftedal.no/blog/?blogid=127 and http://erlend.oftedal.no/blog/?blogid=134

Erlend
  • 2,195
  • 14
  • 13