Categories
Security

Best Security Practices for Node.js Apps

Spread the love

Like any kind of apps, JavaScript apps also have to be written well.

Otherwise, we run into all kinds of issues later on.

In this article, we’ll look at some best practices to avoid creating security holes in our Node.js apps.

noAssert Flag in Buffer

We shouldn’t set noAsserr to true to skip validation of the offset .

Otherwise, we may be able to set the offset to be beyond the end of the Buffer .

Dynamic Code in exec

We shouldn’t dynamic code in exec .

This way, we avoid attackers being able to inject commands they want to run on our server.

For instance, we should write:

child_process.exec('ls', (err, data) => {
  console.log(data);
});

But we shouldn’t write:

const path = "user input";
child_process.exec(`ls -l ${path}`, (err, data) => {
  console.log(data);
});

We shouldn’t have any dynamic expression in the first argument.

This way, there;’s no way that attackers can run commands on our server.

To run commands with arguments, we can do it with execFile :

const child_process = require('child_process');

const path = "./foo/bar"
child_process.execFile('/bin/ls', ['-l', path], (err, result) => {
  console.log(result)
});

We only inject the arguments that we want to add in the place we want it rather than letting anyone enter anything.

Likewise, we can also use spawn :

const child_process = require('child_process');

const path = "."
const ls = child_process.spawn('/bin/ls', ['-l', path])
ls.stdout.on('data', (data) => {
  console.log(data.toString());
});

It’s the same as execFile .

Users can’t run subcommand in the shell.

However, running things like /bin/find may still let users take over our system.

No Mustache Escape

We shouldn’t set object.escapeMarkup to false .

This can let some template engines to disable escaping in HTML entities.

Therefore, this value may allow attackers to do cross-site scripting on our app.

We shouldn’t let users enter something like:

<body onload=alert('foo')>

end run it directly.

Don’t use eval

eval is definitely a bad function that we shouldn’t use.

It lets us run expressions from a string.

Therefore, it leads to attackers being able to run code that they want as well.

Allowing anyone to run code they want if definitely not good.

Use the CSRF Middleware to Prevent CSRF Attacks

Cross-site request fogery our CSRF is an attack where attackers can run requests on a site without authorization.

This can happen when a user goes from a legit site to a malicious site but still has credentials for the legit site.

We should the csrf middleware to prevent CSRF attacks.

When we use it, we shouldn’t use the methodOverride middleware method in our Express app to over the method of the requests with the post key or with the x-http-method-override .

The method override functionality can bypass the CSRF token check provided by the csrf middleware.

Therefore, we shouldn’t call express.methodOverride in our Express app.

However, we should note that with the same-origin policy for Ajax requests, using the x-http-method-override header will be much harder.

No Dynamic File Paths when using fs Methods

We shouldn’t use dynamic file paths when using fs methods.

This way, attackers can’t access different paths in our system which we don’t want people to access.

We don’t want people to traverse paths with ../ or ./ .

No Non-Literal Regex

A regex shouldn’t be dynamic. This way, no one can change them.

Some regex may hang our Node apps.

They include regex with lots of groups and also checking against long strings.

No Nonliteral require

We shouldn’t have dynamic arguments in our require function calls.

This way, attackers can’t pass in their own string to look up modules and use them.

require looks up modules by their path and also in the node_modules folder.

No Insecure Comparisons

We shouldn’t use insecure comparisons that check input sequentially.

They include == , != , !== , and === .

These can lead to timing attacks.

Strings are checked one character at a time.

So these operators would iterate through each character and compare each of them.

Attackers can use the timing of comparisons to work backward to see how many characters match, making cracking passwords easier.

Conclusion

In addition to getting apps to work, we should also make sure that they’re secure.

We got to think about security when comparing string and evaluating dynamic expressions.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *