Set Up Secure Networking for Node.js Applications

Compared to the widely used LAMP (Linux Apache MySQL PHP) or LEMP (Linux Nginx MySQL PHP) stacks, Node.js acts as both the interpreted language (PHP) and the web server (Apache/Nginx); see the following graphic. Node.js handles the communications within the application as well as with outside components.

We have full control over network setup and traffic from our Node.js code and don’t have to worry about another layer outside the codebase doing something we don’t know about, such as serving an index or allowing someone to access a file stored in one of the internal directories.

The lack of outside default configuration is at once both good and bad. It’s good because our server does only what we say it can do, similar to how whitelisting works. It’s bad because most developers don’t know all the caveats of every request type, making their implementations likely to contain common mistakes.

Luckily Node.js has a vibrant ecosystem, with thousands of modules to solve common problems. We get to pick and choose the ones we need for our current application. So while we’re not forced to write everything from scratch, we still need to understand how the modules work. Otherwise, we’re back to the problem where we don’t know what’s happening with our application.

Although there are benefits to having Node.js handle all the network configuration, I still recommend using Nginx for static file serving. One reason is that Node.js is a single-threaded process, as we discussed previously. Every second or millisecond the application wastes reading files from disk and sending them to the users is time it’s not responding to other requests. That’s a lot of time lost if the application responds to twenty image requests for one page load.

And the other reason is that, frankly, Nginx is better at it. Nginx excels at caching and serving static files, and you should always try to use the best tools for the job.

From a security standpoint, why should you care about this? Well, availability is one of the three pillars of web application security. Attackers can try to knock your application offline by overwhelming it with requests. If you reduce the load on your Node.js process, your application becomes more resilient to traffic overload.

Use TLS and SSL to Secure Your Connections

How would you like it if someone could observe every move you made online, not to mention your login credentials to every site and your credit card information? You probably wouldn’t be thrilled (maybe you would, no judgment here), and trust me, neither would your users. You can stop attackers from listening in by encrypting network traffic between your application and the user using Transport Layer Security (TLS) or its predecessor Secure Sockets Layer (SSL), which are more commonly known as HTTPS.

We won’t go into a lot of detail about TLS and SSL here, but I recommend reading up on various attack methods against TLS and SSL.[17] For our purposes, we’ll just set up an HTTPS server and assume the rest is taken care of.

To set up an HTTPS server in Node.js, we just need valid SSL certificates generated by a certificate authority (CA). Many developers use self-signed certificates during development, but these certificates throw red flags in browsers and don’t protect you from eavesdroppers. Self-signed certificates are okay for development purposes but should never be used in production environments.

There are several ways to generate a self-signed certificate, including online generators like the one at cert-depot,[18] and plenty of documentation[19] available for your reference. For the following examples, we’ll use self-signed certificates since they’re easier to obtain, but make sure you apply for CA-generated certificates to use in production. The setup process is the same, so what you learn here will still apply to your production certificates.

Do Not Use Self-Signed Certs in Production!

images/aside-icons/info.png

Self-signed certificates aren’t secure enough to use in production. Without a trusted CA-signed certificate, you’re protected against the most basic attacks and not much else. The security levels vary depending on the type of certificate you buy, so consider your application requirements during the selection process. There are several sources for free certificates, including startssl.com.[20]

With a certificate in hand, you can use the following example to set up an HTTPS server using Node.js:

 'use strict'​;
 
 var​ fs = require(​'fs'​);
 var​ https = require(​'https'​);
 
 var​ options = {
  key: fs.readFileSync(__dirname + ​'/certs/key.pem'​),
  cert: fs.readFileSync(__dirname + ​'/certs/cert.pem'​)
 };
 
 https.createServer(options, ​function​ (req, res) {
  res.writeHead(200);
  res.end(​"hello world "​);
 }).listen(8000);

It’s just as simple using the express framework, as this example shows:

 'use strict'​;
 
 var​ fs = require(​'fs'​);
 var​ https = require(​'https'​);
 var​ express = require(​'express'​);
 
 var​ app = express();
 app.get(​'/'​, ​function​ (req, res, next) {
  res.send(​'hello world'​);
 });
 
 var​ options = {
  key: fs.readFileSync(__dirname + ​'/certs/key.pem'​),
  cert: fs.readFileSync(__dirname + ​'/certs/cert.pem'​)
 };
 
 https.createServer(options, app).listen(8000);

And it really is that simple to configure an HTTPS server in Node.js. As you can see, getting the certificates is the biggest hassle in this whole process.

Let’s Encrypt!

images/aside-icons/info.png

Let’s Encrypt[21] is a free, automated, and open certificate authority brought to you by the Internet Security Research Group (ISRG). It aims specifically to solve the hassle of obtaining, installing, and updating a certificate to encourage the adoption of SSL across websites.

Just remember, though, that Node.js does not automatically redirect from HTTP to HTTPS. So be sure to set up a simple HTTP request handler for redirection:

 http.createServer(​function​ (req, res) {
  res.writeHead(301, {
  Location: ​'https://'​ + req.headers.host + req.url
  });
  res.end();
 }).listen(80);

Or use the express framework:

 var​ httpApp = express();
 httpApp.get(​'*'​, ​function​ (req, res){
  res.redirect(​'https://'​ + req.headers.host + req.url);
 });
 httpApp.listen(80);

Although in this section we looked at how to set up an HTTPS site using Node.js, I must point out that you should use Nginx or other servers in front of your Node.js application to handle the SSL connection. Setting up an SSL connection is expensive, and as Node.js is single threaded, it would suffer in performance when having to deal with many SSL handshakes. Also, dedicated server software is much better at creating and handling SSL connections, with support for newer advanced HTTP features such as HTTP2.

Add HSTS to the Connection

Although we’ve now set up our HTTPS connection, it doesn’t mean our work is done, since there are attacks designed to break SSL like SSL-stripping attack methods that trick browsers into downgrading an HTTPS connection to HTTP on the initial request. This allows the attacker to eavesdrop the protected traffic. To protect our connection we should set up HTTP Strict Transport Security, or HSTS.

The mechanism of HSTS is to send a Strict-Transport-Security header to the client specifying when the SSL policy will expire. The browser will then default to HTTPS when communicating with the application until this header expires. The following graphic illustrates the difference.

Let’s set this header using some simple express framework middleware:

 app.use(​function​ (req, res, next) {
 var​ aYear = 60 * 60 * 24 * 365;
 // Set the Strict Transport Security header for a year
 // Also include subdomains
  res.set(​'Strict-Transport-Security'​,
 'max-age='​ + aYear + ​';includeSubdomains'​);
 
  next();
 });

The header is respected by the browser only if it’s sent over an HTTPS connection and there are no errors with the certificate. Yet another reason you need a proper certificate!

If you are using Nginx or another proxy in front of your Node.js application as recommended, then you should set protection headers in the proxy configuration to reduce distribution of this knowledge all over the application.

Once the header is received, the browser will start defaulting to HTTPS on your site. The header can be updated on the fly, so you can keep the policy active as long as necessary.

Unfortunately, HSTS doesn’t protect the first request ever made by the user to the application. Some browsers work with this limitation by referencing a predefined list of sites using HSTS. Since the list isn’t exhaustive, it protects only a limited number of sites. Even with the limitation, setting the header on the first request makes sense because it drastically narrows the possible attack window.

We won’t go into more detail here, but Mozilla has a nice page with more information about the HTTP Strict Transport Security header.[22]

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.147.140.206