Recently working on a Rails-based web application for a company, I had to look into XSS vulnerability. It turns out that the application, in some places, could take an HTML tag (e.g., <script>jscodehere</script>
directly as a parameter in GET or POST requests.
This parameter is then accessible via the application's params hash (the hash where all incoming key/value data is made available from the request).
Now, the XSS vulnerability stemmed from the fact that the site also makes available the data of many of its pages in a JSON version (e.g., /cart/1.json
).
Through some mechanisms I don't fully understand (I suppose this is technically "Reflected XSS"?), the unsanitized <script>
code which has then made its way into the JSON can be used to compromise personal machines and other sites, through unintended execution.
My question is, why is this not an opt-in system? Rails is now in version 4, so I'm surprised a solution still must manually be built, but this would apply to any web application framework. It's one thing to allow the params to come in unsanitized by default (perhaps the HTML tags will be used in a user's profile page and the formatting is required) – and I think Rails does some scrubbing on the actual rendering action as well, limiting output, by default, to only "safe" html tags.
However, when rendering JSON, it does no such sanitizing/scrubbing, perhaps because when the JSON response is built up and parsed it is too customized to do so, but I don't fully understand why
1) Some built-in mechanism isn't in place
2) This isn't being talked about more–I could find no discussion of unsafe passing of HTML/Script tags in JSON rendering from Rails or Sinatra apps on the web (I could only find a tiny amount of information about Sanitizing the params hash, so sanitizing values on the way IN, which arguably is better, but may not work for everything, as it is a one-size-fits-all solution; you may want to retain some HTML tags but only strip out <script>
tags, for example).
3) Why, in the Ruby world, at least, there is only at present one library which exists for sanitizing (the Sanitize Gem, and it really only works on String datatypes–you have to write your own recursive code to sanitize a Hash, like the params hash, and there seems to be nothing written on this, either!). Rails does have a built-in sanitizer, but it is considered inferior to this third party Sanitize Gem, and is not as flexible when it comes to having a few levels of strictness in how deeply to sanitize (a string).
Am I misunderstanding the validity of injection into JSON as a vulnerability, or has this vulnerability largely been overlooked because JSON is not a core feature of all web applications?
End result: I used a before-filter in the main application controller on the back end to sanitize the params hash every time it comes in from a request, using the Sanitize library.
However, I believe this significantly slowed down the application because it has to happen on every request, and the Sanitizer is essentially running a series of regex calls in a recursive fashion on the hash. This way no tags ever enter the database, and can also never make it out via JSON, but it is a costly hit performance-wise. Is there a better way?