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.
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: To conclude this part, the keys should have a minimum length to validate the requirements of HMAC:
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: 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 |