Is it possible to XSS exploit JSON responses with proper JavaScript string escaping

Chris Mountford picture Chris Mountford · Jun 30, 2010 · Viewed 70.7k times · Source

JSON responses can be exploited by overriding Array constructors or if hostile values are not JavaScript string-escaped.

Let's assume both of those vectors are addressed in the normal way. Google famously traps JSON response direct sourcing by prefixing all JSON with something like:

throw 1; < don't be evil' >

And then the rest of the JSON follows. So Dr. Evil cannot, using the sort of exploit discussed here http://sla.ckers.org/forum/read.php?2,25788 get your cookie (assuming you're logged in) by putting the following on his site:

<script src="http://yourbank.com/accountStatus.json"> 

As for string escaping rules, well if we're using double quotes, we need to prefix each with a backslash and each backslash with another backslash etc.

But my question is, what if you're doing all of this?

Burpsuite (the automated security tool) detects embedded XSS attempts that are returned unHTML-escaped in a JSON response and it reports it as an XSS vulnerability. I have a report that my application contains vulnerabilities of this kind but I am not convinced. I've tried it and I can't make an exploit work.

So I don't think this is correct, but I ask you StackOverflow community, to weigh in.

There is one specific case, that of IE MIME-type sniffing that I think could result in an exploit. After all, IE 7 still had the "feature" that script tags embedded in image comments were executed regardless of the Content-Type header. Let's also leave such clearly stupid behaviour aside at first.

Surely the JSON would be parsed by either the native JavaScript parser (Window.JSON in Firefox) or by an eval() as per the old default jQuery behaviour. In neither case would the following expression result in the alert being executed:

{"myJSON": "legit", "someParam": "12345<script>alert(1)</script>"}

Am I right or am I wrong?

Answer

rook picture rook · Jun 30, 2010

This potential xss vulnerability can be avoided by using the correct Content-Type. Based on RFC-4627 all JSON responses should use the application/json type. The following code is not vulnerable to xss, go ahead test it:

<?php
header('Content-type: application/json'); 
header("x-content-type-options: nosniff");
print $_GET['json'];
?>

The nosniff header is used to disable content-sniffing on old versions of Internet Explorer. Another variant is as follows:

<?php
header("Content-Type: application/json");
header("x-content-type-options: nosniff");
print('{"someKey":"<body onload=alert(\'alert(/ThisIsNotXSS/)\')>"}');
?>

when the above code is viewed by a browser the user was prompted to download a JSON file, the JavaScript was not executed on modern versions of Chrome, FireFox and Internet Explorer. This would be an RFC violation.

If you use JavaScript to eval() the JSON above or write the response to the page then it becomes DOM Based XSS. DOM based XSS is patched on the client by sanitizing the JSON before acting on this data.