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 we should follow when writing Node apps.
Block Cross-Site Request Forgeries
We should block cross-site request forgeries.
This is an attacker where attackers can attempt to put data into an application via their own site.
The attacker creates a request with a form or other input that creates requests against an app.
To mitigate cross-site request forgeries, we can use the csurf package.
For instance, we can write:
const express = require(‘express’);
const csrf = require('csurf');
const app = express();
app.use(csrf());
app.use(function(req, res, next){
res.locals.csrftoken = req.csrfToken();
next();
});
We use the csrf
middleware so we can get the CSRF token with the csrfToken
method.
Then we can use it in our template with:
<input type="hidden" name="<i>csrf" value={{csrftoken}} />
Don’t Use Evil Regular Expressions
Evil regex includes grouping with partitions, repetition, and alternation with overlapping.
These patterns can take exponential time to computed when applied to certain non-matching inputs.
Examples of these patterns include:
(a+)+
([a-zA-Z]+)*
(a|aa)+
If check against some input like aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
, then we would hang our app.
It can take seconds or minutes to complete the pattern check.
We can audit evil regexes with:
Add Rate Limiting
Rate limiting will protect us from DOS attacks.
We don’t want attackers to bombard our app with lots of requests and let them all go through.
To limit the number of requests to our app from one IP address, we can use the express-limiter package.
For example, we can write:
const express = require('express');
const redisClient = require('redis').createClient();
const app = express();
const limiter = require('express-limiter')(app, redisClient);
limiter({
lookup: ['connection.remoteAddress'],
total: 100,
expire: 1000 * 60 * 60
})
We use the limiter
middleware to limit requests up to 100 per hour per IP address.
total
is the number of requests.
expire
is when the limit is reset.
Docker Compose
We can create our Docker compose config to install Nginx with our app together.
For instance, we can write:
web:
build: ./app
volumes:
- "./app:/src/app"
ports:
- "3030:3000"
command: pm2-docker app/server.js
nginx:
restart: always
build: ./nginx/
ports:
- "80:80"
volumes:
- /www/public
volumes_from:
- web
links:
- web:web
We install Nginx and our app all in one go with our Docker compose file.
Keep a Clear Separation Between the Business Logic and the API Routes
We should keep a clear separation between the business logic and the API routes.
We definitely shouldn’t have our logic in our API routes since a route can do many things.
We need a service layer with all the business logic so that we can work with and test them separately.
Also, we can use everything easier.
Use a config Folder for Configuration Files
Configuration files should be in a config
folder so that we can add all the configuration into one place.
It’s easy to find and change this way.
Conclusion
Evil regex and folder structure should be taken into consideration when we create our Node app.