When we use an Express app for production usage, i.e. it’s used by external users, we have to be careful about security since it’s available to the outside world.
In this article, we’ll look at some security best practices when running Express apps in a production environment.
Ensure Dependencies are Secure
We can check if the Node packages we use in our apps are secure by using NPM’s automatic security check when we install packages.
We can also run manual security checks with npm audit
.
Both commands check the Node packages we use for security vulnerabilities.
To stay even more secure, we can use Snyk. It offers a command-line tool and Github integration to check our repositories automatically against a list of security vulnerabilities that Snyk has.
It’s available as a Node package. To install it, we run npm i -g snyk
.
We can use snyk test
to test our apps for vulnerabilities.
snyk wizard
is a command-line wizard that walks us through the process of applying updates to fix vulnerabilities that were found.
Avoiding Other Known Vulnerabilities
We can check the Node Security Project website or Snyk advisories that may affect Express and other Node modules that we use in our app.
These databases are great resources for learning about Node security.
We also have to be aware of general web vulnerabilities that are in the wild on the web.
Cross-Site Request Forgery
Cross-site request forgery (CSRF) is a vulnerability where an attack can make unauthorized requests to our app as the user that our app trusts.
Attackers can do this in many ways like specially crafted commands, image tags, hidden forms, JavaScript XMLHttpRequests, etc.
We can use the csurf middleware to protect our app from CSRF attacks. It adds a req.csrfToken()
function so that we can check against the CSRF token when we handle requests to make sure that the request is actually coming from users we trust.
Filter and Sanitize Inputs
We should filter and sanitize inputs so that attackers can’t run code in our system.
Sanitizing inputs help with this since strings with special characters may be directly injected into code in some places.
To prevent input strings from having special characters that are part of some malicious code snippet, we should escape those characters so they’re turned in more harmless characters.
SQL Injection
Preventing SQL injection attacks is another reason to sanitize inputs. Not only that we should sanitize inputs, but we should also make sure that input strings are never directly injected into SQL statements.
If we let strings be interpolated straight into SQL commands, then attackers can run anything they wish.
We definitely don’t want that to happen because they may run commands to steal, data, corrupt data, destroy our database and more.
To prevent SQL injection, we should use parameterized queries and prepared statements.
Prepared statements will sanitize inputs before running them so that we don’t have to interpolate values into SQL command strings directly.
For example, if we use SQLite as our database in our Express app, we can write something like:
app.post('/', (req, res) => {
const { name, age } = req.body;
db.serialize(() => {
const stmt = db.prepare('INSERT INTO persons (name, age) VALUES (?, ?)');
stmt.run(name, age);
stmt.finalize();
res.json(req.body);
})
})
In this case, name
and age
are sanitized before the prepared statement:
INSERT INTO persons (name, age) VALUES (?, ?)
is run.
name
and age
are sanitized and replace the question marks when we run:
stmt.run(name, age);
db.prepare
is a method in the SQLite3 package. Other database libraries should also support prepared statements.
We can use the sqlmap tool to detect SQL injection vulnerabilities in our app.
Testing TLS Security
We should use the nmap and sslyze tools to test the configuration of our SSL /TLS ciphers, keys, renegotiation, and validation of our certificates.
nmap is a utility for network discovery and security audits. It does a variety of scans to check for vulnerabilities in our systems.
sslyze is used specifically for SSL/TLS scanning to check for configuration issues with our SSL/TLS setup.
Check for Regular Expression Denial of Service Attacks
Regular expression denial of service attacks (ReDoS) is an attack that exploits the fact that most regex implementations may reach extreme situations to make them work extremely slowly.
Attackers can send inputs that make our app that enter these extreme situations and make our app hang.
Grouping with repetition of various kinds are examples of regexes that may be subject to this kind of vulnerability.
We can use safe-regex to check that our regexes aren’t susceptible to (ReDos) attacks.
Conclusion
When we put our Express app in a production environment, there’s more to think about than just getting our app to work.
We have to be aware of SQL injection attacks and other code injection attacks so that our apps won’t run malicious code. To do this, we sanitize inputs and run SQL queries as prepared statements.
Also, we have to be aware of SSL/TLS security and check if our server configuration is secure by using various utilities to check our server configuration.
Our app’s dependencies should be checked for vulnerabilities so that we can update them to avoid the security issues.
Finally, we should make sure the regexes that we use aren’t vulnerable to (ReDoS) attacks, which may bring down our app.