KoaJS Security Tips

In this article, I explain how to use KoaJS in a production environment, avoiding the vulnerabilities induced by the default configuration, and a tool to test your own website.

Dec 30, 2019 by Nicolas Béguier

How to use KoaJS without expose your users

According to KoaJS description, this is an Expressive HTTP middleware framework for node.js to make web applications and APIs more enjoyable to write.
There are about 30k stars on GitHub, downloaded 200k times this week and it's a dependency of almost 4k npm packages.

We could assume that a lot of public websites are using it.

Session cookie vulnerable by default

In every GitHub example, they specify app.keys as a list of strings. If you are doing it, you are vulnerable to an offline known-plaintext attack. koajs/koa uses the library pillarjs/cookies, which is using crypto-utils/keygrip to sign and verify the session cookie.

In the koajs/koa package, a new Cookies is created if none exists: The Cookies function is taking options as a third argument. This argument takes a structure with the keys parameter equal to the app.keys value in the configuration.

In the index.js of pillarjs/cookies: In the Cookies function, only the else condition matches the koajs/koa options values. If options. keys is an array, it returns a new Keygrip object, with the default hash algorithm and encoding method, respectively SHA-1 and base64. In the other case, it returns options.keys, no matter what it is.

To sign the session cookie, Keygrip is doing an HMAC(algorithm, keys) of the session cookie, encodes it and replaces some characters.

Using HMAC is still secured in production, but when it's configure in a proper way. Since SHA-1 is broken, you have to be very careful of how HMAC is imlemented in your production. Two options are possible, setting an app.keys of an array of 20 bytes long strings, or using a stronger hash function: SHA-2.

To override this encryption algorithm we need to set the options.keys parameter as a Keygrip constructor which redefined the hash function and the encoding method.

It leads to this configuration : The KoaJS team knows this flaw and have been warned. Some pull-request to patch multiple README has been merged.

These PR added a "security" part in the README to help users to copy & paste something secured. This comment explains very well the issue I'm talking about:

tl;dr the content of the cookie is not encoded, only the .sig when signed is used. Also, by default it uses the sha1 algorithm to generate the .sig cookie, which can be cracked in minutes.

To conclude this part, the keys should have a minimum length to validate the requirements of HMAC:
Hash algorithm Minimum key length
SHA-1 20 bytes
SHA256 32 bytes
SHA512 64 bytes

If you enjoyed this story, please recommend and share to help others find it! Feel free to contact me if you have any questions.