- Those who cannot remember the past are condemned to repeat it.
- George Santayana, The Life of Reason, Volume 1, 1905
US (Spanish-born) philosopher (1863 - 1952)
This oft repeated quote needs to be tweaked just a bit to be more applicable to web application security:
Those who choose to ignore the past in favor of convenience are condemned to repeat it.
Just how many times do developers have to “hack” a protocol that eventually becomes a wide-open hole through which even a blind miscreant could drive a tank before they stop repeating the mistakes of the past?
I am sure that, given time, I’ll grow less angry about the attitude toward the creation of this but at the moment I’m nothing short of aghast at the indifference toward security with which this risk is discussed.
The “nothing serious” hack is the use of a custom HTTP header, X-JSON, to transport JSON encoded data to be evaluated immediately by the Prototype framework.
This was apparently conceived of in an attempt to avoid using multipart-encoded messages when sending responses of mixed JSON and HTML back to clients. Granted, the developers who looked for a better solution were right: multipart-encoded messages are ugly, difficult to parse, and a pain in the rear to deal with. But “using HTTP headers in a way we shouldn’t” and introducing yet another potential security hole in web applications is just lazy at best and irresponsible at worst.
Perusing the web in search of more information about this potential security risk we find Ruby developers claiming the hack is “nothing serious” even while admitting they shouldn’t be using HTTP headers to transport application data. About X-JSON header and evil things… from the Ruby Forum:
Let us get something clear - the X-JSON header is a hack. Nothing serious, just a small hack which simplifies returning two types of data (HTML andapplication/json) at the same time. Of course we're using HTTP headers in a way we shouldn't, but has anyone seen how multipart-encoded message looklike? Our header hack is way nicer and technically simpler than that kind of encoding.
The X-something headers are reserved for custom (proprietary) usage. We have the freedom to use them in any way we want to, and we have taken thatliberty to do some highly conventional JSON magic. [emphasis added]
The attitude of simplicity, as usual, winning over security is not confined to Ruby developers as we see from this tale related by a Python developer:
One of the demo sites I was working on this week needed to pass a small amount of JSON back with it's page results. There are a few ways to do this (and I'd suggest this post, "Loading Content with JSON" as a starting point if you're looking for ideas), but for simplicity, I decided to take advantage of the automatic X-JSON HTTP Header parsing feature in Prototype 1.5.0. (The Ajax.Request docs address this capability.) [emphasis added]
I will not disagree with the statement that passing application data via an HTTP header is simpler than messing with the alternatives. But it is fraught with additional security risks.
- The client almost never validates input from the server. The server is viewed as a trusted source of data. Recent reversals of SQLi as a method of infecting clients rather than application data, however, should force developers to revisit the assumption that data received from the server should be automatically trusted.
- It is moderately difficult for any type of security mechanism – web application firewall, mod_security, code – to ascertain the validity of JSON without evaluating it in the same manner as it would be evaluated by the client parser.
- Most secure coding techniques and commercial solutions such as web application firewalls do not expect to find potentially tainted application data hanging out in the HTTP headers. Cookies, yes. Hiding in custom headers? No.
Because of this, the use of the X-JSON custom header to transport [potentially tainted, malicious] application data should be avoided. In fact, if I were to offer an immediate solution I’d say use network-side scripting to remove the offending HTTP header before it is delivered to the client. Use mod_security, use iRules, use something capable of intercepting web application data and inspecting it, then remove any instance of X-JSON you find. Yes, you’ll break the application, but perhaps that’s exactly what needs to be done to get the point across: this is an avoidable, unnecessary security risk against which our customers have no defense. It is irresponsible of us to use it. Find another way.
Granted, the use of JSON as an application protocol has only become widely accepted in the past 18 months, but even so – it is not immune to exploitation. And as it continues to be one of two formats commonly offered by Web 2.0 APIs (the other being the equally exploitable XML) it is likely only a matter of time before it becomes a target of opportunity for those attempting to find easier ways to infiltrate clients and spread their disease.
The reason for the anger toward the casual dismissal of the use of the X-JSON header as “nothing serious” and the failure of developers to see this use as the potential security risk it is centers around the fact that this is a completely avoidable risk. This is not one of those “we had no choice” risks; this is 100%, absolutely avoidable. There is no reason that this risk need be incurred, except as admitted to by a variety of developers on the web: it’s easier than doing the right thing.
I’ll say one thing for the developers, they have the basic premise down right. The path of least resistance is the one most people will take. And there isn’t much resistance in terms of security in the use of the X-JSON header and automatic evaluation of potentially tainted application data. So how long do you really think it’s going to take “the bad guys” from deciding that they, too, like the path of least resistance?
One of the Ruby developers stated: “We have the freedom to use them [custom HTTP headers] in any way we want to.”
Freedom incurs responsibility, and in this case it’s the responsibility to ensure that the solution used is secure and doesn’t introduce unnecessary risk. Seems to me that some developers are forgetting that part of “freedom.”
Secure coding in theory is a great thing – but you have to actually apply the principles in the first place for it to work.
Related posts & articles: