JavaScript and the Art of Motorcycle Maintenance

There's a little-known problem related to ColdFusion's native JSStringFormat() function and its use in html script tags. In the event that a user enters the string "</script>" into a form in your application and that data is later placed into a javascript literal inside of a pair of script tags, it causes the browser to close the script tag early and produces an unclosed string-literal error. For example:

<script language="JavaScript" type="text/javascript">
alert('#jsstringformat("</script>")#');
</script>

This code will cause the browser to throw the unclosed string-literal JavaScript error, and consequently the alert dialog won't display. Now I'm not claiming this is a bug, because technically in most cases functions that perform a similar task for other mediums, such as URLEncodedFormat() or HTMLEditFormat() only escape a given character if it is described by the documentation for the language or medium as a "meta character", or in other words, if it has pertinent symbolic meaning which causes the interpreter to take some action other than displaying the character within a string literal. In the case of JavaScript for example, the backslash, single and double-quotes, carriage return and line feed are all "meta characters" and would be escaped like this "\\\'\"\r\n". Since none of these characters appear in the string "</script>" JSStringFormat doesn't escape them.

Now because it's not very common for users to enter the string "</script>" into an input element, most ColdFusion programmers haven't seen this (yet). It does however present the possibility of allowing cross-site scripting (XSS) attacks. And because most ColdFusion programmers haven't seen it (and because modern browsers are somewhat forgiving about < and > characters in script literals), most programmers don't anticipate it or take any precautions against it. What this means is that very nearly 100% of applications that currently use JSStringFormat() for the purpose of formatting JavaScript string literals are vulnerable to this variety of XSS attack (assuming the server's script-protect feature is disabled, which is usually the case).

For my money, they shouldn't be forced to learn about it to protect themselves. There exists a proven solution to this problem already which can be seen in the way that SerializeJSON() formats strings. The folks responsible for JSON made a smart decision to escape the forward-slash, so the string "</script>" becomes "<\/script>". This is okay because it's a documented behavior of JavaScript that the escape character \ when followed by any other character will treat the following character as a literal value instead of a "meta character". The forward slash isn't a meta character in JavaScript to begin with, so the engine doesn't have to do anything (and it doesn't). Meanwhile the browser isn't seeing the script tag closed early and both the HTML engine and the JavaScript engine are happy, no errors and no XSS attacks.

Now that there are umpteen applications in the wild using JSStringFormat() however, it's unrealistic to expect all the developers who've created them to retrofit them with SerializeJSON() for all their string values or even necessarily to start using SerializeJSON() for new applications. I feel JSStringFormat() should format strings the way SerializeJSON() does. The larger community however mostly balk at this suggestion.

"Hermes Conrad, you are technically correct, the best kind of correct!"
— Futurama

So here is my synopsis of all the arguments against changing the JSStringFormat() function.

  1. the function behaves the way it was designed to behave, in accordance with common conventions for formatting functions - therefore it's the programmer's responsibility to see this coming (subsequent arguments mostly boil down to supporting or justifying this argument that responsibility falls on the programmer)
  2. Nobody said it would be safe in every environment
  3. It's an edge case
  4. JavaScript isn't always output in html script tags (i.e. <a onclick="alert('#JSStringFormat("</script>")#')">show it</a>) or in HTML in general
  5. The fact that SerializeJSON() works isn't proof that the solution is safe
  6. Making JSStringFormat behave differently than URLEncodedFormat or XmlFormat would be worse than the status quo
  7. It might cause a problem later (related to the previous item)
  8. We would have to anticipate the needs of any future browser (again, related to previous item)

And an analogy:

Assumed:

  • four-wheeled automobiles are currently sold without any protection on the front or rear fender
  • occasionally automobiles are damaged as a result of bumping into another automobile on the street - this happens mostly to the front and rear fender
  • an after-market product called a "bumper" can be purchased and installed on the front and rear fender to reduce or eliminate damages from low-speed collisions
  • most car owners don't purchase bumpers in spite of their low cost and ease of installation

Recommendation: Bumpers are cheap and easy to install, manufacturers might install them as part of the vehicle's original equipment, eliminating the need for car owners to purchase after-market bumpers and saving them money on repairs in the long-run from low-speed collisions.

Objections:

  1. Vehicles aren't designed to collide with each other -- therefore it's the driver's responsibility to protect their car
  2. Nobody said cars would be indestructible
  3. It's an edge case (how often do you rear-end someone at under 5mph or vice versa? It's not very often is it? -- the potential however exists nearly 100% of the time you're driving, just as in the case of JSStringFormat() with most ColdFusion applications)
  4. People don't always drive on the street around other cars, i.e. some people like to drive "off-road", an environment in which the bumper isn't so relevant
  5. The fact that many people purchase and use after-market bumpers isn't proof that they're safe
  6. Other vehicles such as boats, motorcycles and airplanes don't have preinstalled bumpers - deviating from the standard would be unexpected and therefore worse than the status quo
  7. People might not anticipate the extra material on the fender and bump into each other more often or catch it on trees, etc.
  8. We can't guarantee that the bumper won't interfere with future developments in the automotive industry

Hence the reason why these objections get my dander up every time.

Comments
BlogCFC was created by Raymond Camden. This blog is running version 5.5.006. | Protected by Akismet | Blog with WordPress