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

78,539

Solution 1

For the record, although I accepted an answer, for the exact literal question I am asking, I was right and there was no vulnerability due to the presence of non-HTML-escaped yet correctly JSON-escaped HTML inside JSON values. There could be a bug there if that value was inserted into the DOM without client-side escaping but Burpsuite has little chance of knowing if that would happen just by looking at network traffic.

In the general case of determining what is a security vulnerability in these circumstances, it's instructive to recognise that while it may not feel like good design, the response content of a JSON value could legitimately be known to certainly contain no user input and be intended to be already rendered HTML to be safely inserted in the DOM unescaped. Escaping it would be a (non-security) bug as I mentioned in another comment.

Solution 2

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.

Solution 3

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.

Maybe it tries to prevent the vulnerability described in the rule 3.1 of OWASP XSS Cheat Sheet.

They give the following example of vulnerable code:

<script>
    var initData = <%= data.to_json %>;
</script>

Even if double quotes, slashes and newlines are properly escaped, you can break out of JSON if it's embedded in HTML:

<script>
    var initData = {"foo":"</script><script>alert('XSS')</script>"};
</script>

jsFiddle.

to_json() function can prevent this issue by prefixing each slash with a backslash. If JSON is used in HTML attribute, the whole JSON string must be HTML-escaped. If it's used in a href="javascript:" attribute, it must be URL-escaped.

Solution 4

If we limit our scope to IE (all versions), assume you are running a site based on PHP or ASP.NET, and ignore the IE anti-XSS filter, then you are wrong: your users are vulnerable. Setting 'Content-type: application/json' will not help, either.

This is due to (as you mention) IE's content detection behavior, which goes beyond sniffing for HTML tags in the response body to include URI analysis.

This blog posting explains this very well:

https://www.adico.me/post/json-based-xss-exploitation

Share:
78,539
Chris Mountford
Author by

Chris Mountford

Software Development, Bitcoin, Electronic Music.

Updated on January 22, 2022

Comments

  • Chris Mountford
    Chris Mountford over 2 years

    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. 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?

    Burp Suite (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.

    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?

  • Chris Mountford
    Chris Mountford almost 14 years
    OK so I suppose I could have made it clearer, but the JSON response I'm talking about is defined by the presence of the Content-Type header having the value "application/json". So it seems you're confirming that there is no exploit. Can't your code can be exploited by direct sourcing on a hostile domain, that is using the script tag and parametising the source to include code that will then be executed in the context of the domain it's from? In that case that domain's cookies would be accessible and could be captured by the calling page using document.write. Right?
  • rook
    rook almost 14 years
    @Chris Mountford the injected JavaScript is not executed because the server is telling the browser not too. Think of it like this, what if you had JavaScript in a .exe? This could lead Dom Based XSS, but so could other designs. Dom based xss executes with the same policy as it is executed from. The only way that this can be a problem for you is if you are eval()ing the code on your own site.
  • Chris Mountford
    Chris Mountford almost 14 years
    My understanding was that JSON was eval()'d very commonly in the past, at least by default on jQuery (as I said). However, I'm interested not in JavaScript injection but in HTML injection in JSON which leads to JavaScript execution. Can you comment on that? Also, as I said IE as recent as v7 I have confirmed can IGNORE the Content-Type header under certain circumstances. Yes this is a bug in IE but Microsoft argued no (regardless of the RFC) and in the end, for security ,it only matters what the browsers do not what the spec says.
  • rook
    rook almost 14 years
    @Chris Mountford The term "js injection" is really bad and I shouldn't have used it, its always XSS and thats the correct term. It is possible to eval() code and have js stuck as data for instance var test='<script>alert(/not_xss/)</script>', if the attacker can inject a single-quote then he can break out and execute javascript. If IE is executing JavaScript in .exe files or other in application data then they should be issued a CVE number. If you can prove this behavior I'll help you submit a Bugtraq post.
  • Chris Mountford
    Chris Mountford almost 14 years
    Thanks for that. For the record, I think javascript injection is an excellent term to disambiguate on one hand the use of the single quote for an escape in situations like this (which I specifically excluded from my original question) and on the other hand, the insertion of html tags to get into a script block.
  • Chris Mountford
    Chris Mountford about 12 years
    OK, but the URI is still totally under the server control.
  • Chris Mountford
    Chris Mountford about 12 years
    I see that the sniffing behaviour of IE creates multiple attack vectors possible, but modifying the path info is not possible on my application. Also, finally I can put this sniffing problem to rest since IE version 8+ will turn off MIME sniffing using this: X-Content-Type-Options: nosniff For anyone reading this, I think I've established that JSON can safely carry values with tainted user input as long as it is JSON value encoded and of course it should never be attached to an HTML DOM without client-side html encoding.
  • Chris Mountford
    Chris Mountford about 12 years
    To clarify, I mean there is no opportunity for attackers to choose their own path info. This means my app has no vulnerability in that category. Also, in my original question, I did state that I wanted to put aside the question of IE's MIME sniffing, because I wanted to concentrate on other categories (I had a workaround for IE's MIME sniffing already).
  • Mark Amery
    Mark Amery over 10 years
    Rook, I haven't read it in detail yet, so forgive me if I've misread or am just plain being thick, but I believe that this blog post, provided by @anon below, describes an attack by which Internet Explorer can be made to treat responses with the application/json Content-type as though they were HTML, allowing reflected XSS attacks despite the header. If I'm understanding all this correctly, it means that your answer here is wrong. Perhaps you'd like to have a look at this?
  • rook
    rook over 10 years
    @Mark Amery Yes, you are mistaken. JSON parsing won't come into play, the browser will not evaluate executable code in the JSON body for any cross-site request. But don't take my word for it, this is very easy to test and in fact I have provided the source code to conduct this test! Not testing your own security is the source of all vulnerabilities.
  • Mark Amery
    Mark Amery over 10 years
    @Rook You've dismissed the post too early. The bit about eval was in an intro passage about previously known exploits, and obviously only applies if the JSON response is being parsed somewhere using eval. If you continue reading, the actual vulnerability being described starts after the line that says we have discovered a way to render JSON responses in IE by direct browsing. I've posted my own answer describing this (although the painful level of detail is for the sake of people unfamiliar with XSS - I know it's not necessary for you!)
  • Chris Mountford
    Chris Mountford over 10 years
    This is a very basic bug in the php (I assume it's php). You must not inline tainted data into HTML without HTML escaping. But as I indicated in my question, I am not doing this. While it's possible that Burpsuite may be trying to prevent this problem, that approach is misguided.
  • Alexey Lebedev
    Alexey Lebedev over 10 years
    What approach is misguided? I don't understand you. As for "You must not inline tainted data into HTML without HTML escaping.", guess what, you shouldn't inline even untainted data without escaping.
  • Chris Mountford
    Chris Mountford over 10 years
    The matter of what you can inline is completely outside the scope of this question. You can certainly inline untainted data if that data is composed of HTML. In fact if you have HTML and you inline it WITH escaping, you will end up with double escaped output, which, while not a security bug, is still a bug. The approach I describe as misguided is the attempt "to prevent the vulnerability described in the rule 3.1 of OWASP XSS Cheat Sheet" which you suggest as Burpsuite's intention. If your suggestion about Burpsuite is true, then they are misguided.
  • Prashant
    Prashant almost 4 years
    If however a security tool can't proof the absence of a weakness, it is correct from the tool to alert the necessary pattern. And it might also be worth considering to avoid it even when you cannot immediately see an vector to exploit it. Simply because attackers have more time to exploit emergent properties of a combined system. Especially if some code on your same origin might be unknown to you and still vulnerable.
  • Chris Mountford
    Chris Mountford almost 4 years
    I can see the wisdom in your general comments; tools cannot prove the absence of weaknesses, only fail to find them. This specific case was one of clumsy, incorrect diagnosis. The tool should not misinterpret correctly JSON-escaped string content in JSON Content-Type responses as if they were Content-Type: text/html. To HTML-escape content that is intended to be HTML (not text appearing in an HTML page) is the double escaping bug we all know. Note also that the presence of HTML in JSON can sometimes be known to be free from tainted user data e.g. hard-coded.
  • Prashant
    Prashant almost 4 years
    escaped JSon might be safe for some Browser requests, and the mime type might block some others, but that does not mean it could be still risky for other things, like loading it as a CSS for example. (Scary history here youtu.be/bMPAXsgWNAc ). So if the tool finds reflected text it is good to warn about it (it could influence the severity based on the mime type if it wants to be helpful)
  • Chris Mountford
    Chris Mountford almost 4 years
    @eckes you're describing a class of hypothetical problems where content does not match the request scenario. I assert that you cannot universally protect against that class of problems. In my case, we regularly received 300 page reports of incorrect warnings about our product (~5Mloc). It might seem important to assess these warnings but the benefit of doing that job (instead of fixing real bugs) and the lessons we could learn from these reports depended greatly on their quality and accuracy. False positives are dangerous like in the traditional fairy tale The Boy Who Cried Wolf.
  • Prashant
    Prashant almost 4 years
    I know those 300 page ports and I know that making changes sometimes is easier than to argue about it. Especially in a case where there is a risk of ill behaved clients reduced with it. For example I once got a long list of found malicious binaries only because a route did not retuned 404 on arbitrary (ignored) file names (like /route/virus.exe). Scanners can be pretty dumb
  • Prashant
    Prashant almost 4 years
    (And yes, Security hardening is often worrying about hypothetical instances. While I would agree that this is not a clear cut case there can be made some argument for being frugal with error messages. Especially if it easily trips off scanners as well. After all you can't control when a customer would run a dumb scanner)