Today's Question:  What does your personal desk look like?        GIVE A SHOUT

An Object is not a Hash

  devthought.com        2012-01-19 10:16:10       42,299        3    

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.

  1. var posts = {};

  2. app.post('/create', function (req, res) {
  3.   if (req.body.title && req.body.slug) {
  4.     // avoid duplicates
  5.     if (!posts[req.body.slug]) {
  6.       posts[req.body.slug] = new Post(req.body);
  7.       res.send(200);
  8.     } else {
  9.       res.send(500);
  10.     }
  11.   }
  12. });

Our first stab for trying to avoid duplicates is checking whether the key exists in our object.

  1. if (!posts[req.body.slug]) {

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:

  1. __defineGetter__       __defineSetter__          valueOf
  2. __lookupGetter__       __lookupSetter__
  3. constructor             hasOwnProperty
  4. isPrototypeOf           propertyIsEnumerable
  5. toLocaleString          toString

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:

  1. if (!posts.hasOwnProperty(req.body.slug)) {
  2.   posts[req.body.slug] = new Post(req.body);
  3.   res.send(200);
  4. }

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:

  1. ∞ ~ node
  2. > var a = {};
  3. > a.hasOwnProperty('hasOwnProperty')
  4. 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:

  1. > a.hasOwnProperty = {}
  2. {}
  3. > a.hasOwnProperty('hasOwnProperty')
  4. TypeError: Property 'hasOwnProperty' of object #<Object> is not a function
  5.     at [object Context]:1:3

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:

  1. > Object.prototype.hasOwnProperty.call(a, 'hasOwnProperty')
  2. true

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:

  1. function has (obj, key) {
  2.   return Object.prototype.hasOwnProperty.call(obj, key);
  3. }

And use it as follows:

  1. if (has(posts, req.body.slug)) { }

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/

JAVASCRIPT  OBJECT  HASH  NODE.JS 

Share on Facebook  Share on Twitter  Share on Weibo  Share on Reddit 

  RELATED


  3 COMMENTS


crawlergo@gmail.comAnonymous [Reply]@ 2020-08-12 05:05:37
C
Anonymous [Reply]@ 2020-10-04 09:33:20

This is a dumb convoluted example. Why wouldn’t you define a concrete type? Allowing user input to dictate the keys in your map without any validation seems like an antipattern. 

Anonymous [Reply]@ 2023-07-21 18:51:28

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.

 

??? why you think there will be untrusted user input?

Isn't that already out of problem of being object or not lol