Following my article A String is not an Error, I want to bring attention to an issue that similarly applies to JavaScript in general, but has special relevance in the Node.JS environment.
The problem boils down to the usage of {}
as a data-structure where the keys are supplied by untrusted user
input, and the mechanisms that are normally used to assert whether a key
exists.
Consider the example of a simple blog created with Express. We decide to store blog posts in memory in a {}
, indexed by the blog post slug. For example, this blog post would be posts['an-object-is-not-a-hash']
.
We start writing the route /create
, which takes a few POST fields like “title†and “slug†and passes it to a Post
constructor.
Our first stab for trying to avoid duplicates is checking whether the key exists in our object.
Normally this would work fine, but let’s consider that the user could pick any of the keys that are present in any JavaScript object as a name:
If the user wanted to, for example, name his blog post "constructor"
our program would behave incorrectly. We therefore change our code to leverage hasOwnProperty
, which will allows to check whether the property has been set by us:
Most JavaScript programmers are already familiar with hasOwnProperty
, since in the browser world it’s the standard way of writing libraries that work well in environments where Object.prototype
is modified, so this addition should come to most as no surprise.
The hasOwnProperty trap
Our program, however, is still susceptible to potential misbehaving. Let’s say our user decides to call his blog post "hasOwnProperty"
. The first time our check executes, everything will behave correctly, since the check will return false:
Our code would therefore set the hasOwnProperty
value in our object to the Post
instance, which is an object. We can now simulate what would happen if the user tries that again:
As a result:
- Our code would throw a (potentially) uncaught exception.
- Execution of our
/create
route would be aborted and response would not be sent to the user. - The request would be left hanging until it times out on both ends.
The solution to this problem is to avoid relying on the
“hasOwnProperty†provided by the object we’re dealing with, and use the
generic one from the Object.prototype
. If we execute it on our test subject, true
will be returned after we set it as expected:
Conclusions
The first conclusion from this experiment is that from the moment we
decide to use a JavaScript object as a general-purpose hash table we can no longer rely on any of its inherited properties, specially hasOwnProperty
(which we’re normally bound to use). This oversight, as a matter of fact, afflicted the Node.JS core querystring library in the past.
If your code relies heavily on data structures where the possibility
for collisions like this exist, you might want to consider having a has
utility around:
And use it as follows:
As a side note, you should generally stick to this method in the browser environment as well. Host objects such as window
in older Internet Explorer versions do not have hasOwnProperty
, leading to potentially inconsistent behavior in your code.
Source:http://www.devthought.com/2012/01/18/an-object-is-not-a-hash/