Express.js sikkerhedstip: Hvordan du kan gemme og sikre din app

Tag 7 trin for at sikre dig, at din app er uovervindelig

Er din telefon låst? Har du en pinkode, adgangskode, fingeraftryk eller FaceID? Jeg er 99 procent sikker på, at du gør det. Og det er tydeligt hvorfor - du holder af din sikkerhed. I dag er det lige så vigtigt at holde din telefon beskyttet som at børste tænder om morgenen.

For flittige og opmærksomme softwareudviklere er det lige så vigtigt at beskytte deres telefoner at holde deres app sikker. Hvis du er en udvikler, og du vælger at forsømme den - bedes du overveje din tilgang igen. Hvis du er projektejer, og dit udviklingsteam siger, at datasikkerhed kan vente, bedes du omgå dit team igen.

I denne artikel vil jeg tale om, hvordan man kan sikre, at dit Express.js-projekt er sikkert og uovervindeligt for ondsindede angreb.

Der er 7 enkle og ikke meget enkle foranstaltninger, der skal træffes med henblik på datasikkerhed:

  1. Brug pålidelige versioner af Express.js
  2. Sikr forbindelse og data
  3. Beskyt dine cookies
  4. Sikre dine afhængigheder
  5. Valider dine brugeres input
  6. Beskyt dit system mod brutal kraft
  7. Styr brugeradgang

Lad os se nærmere på hver enkelt.

1. Brug pålidelige versioner af Express.js

Forældede eller forældede versioner af Express.js er en no go. 2. og 3. version af Express understøttes ikke længere. I disse er sikkerheds- eller ydeevneproblemer ikke løst længere.

Som udvikler skal du absolut migrere til Express 4. Denne version er en revolution! Det er ret forskelligt med hensyn til routing-systemet, middleware og andre mindre aspekter.

2. Sikr forbindelse og data

For at sikre HTTP-headere kan du bruge Helmet.js - et nyttigt Node.js-modul. Det er en samling af 13 middlewarefunktioner til indstilling af HTTP-svaroverskrifter. Især er der funktioner til indstilling af indholdssikkerhedspolitik, håndtering af certifikatgennemsigtighed, forhindring af klikjackning, deaktivering af caching på klientsiden eller tilføjelse af nogle små XSS-beskyttelse.

npm install helmet --save

Selvom du ikke ønsker at bruge alle hjelmens funktioner, er det absolutte minimum, du skal gøre, at deaktivere X-Powered-By header:

app.disable('x-powered-by')

Denne header kan bruges til at registrere, at applikationen er drevet af Express, som lader hackere udføre et præcist angreb. Sikkert er X-Powered-By header ikke den eneste måde at identificere et Express-run-program på, men det er sandsynligvis den mest almindelige og enkle.

For at beskytte dit system mod angreb fra HTTP-parameterforurening kan du bruge HPP. Denne middleware lægger sådanne parametre til side, som forespørgsel og forespørgsel, og vælger den nyeste parameterværdi i stedet. Installationskommandoen ser således ud:

npm install hpp --save 

Brug Transport Layer Security (TLS) til at kryptere data, der sendes fra klienten til serveren. TLS er en kryptografisk protokol til sikring af computernetværket, efterkommeren af ​​Secure Socket Layer (SSL) kryptering. TLS kan håndteres med Nginx - en gratis, men effektiv HTTP-server - og Lad os kryptere - et gratis TLS-certifikat.

3. Beskyt dine cookies

I Express.js 4 er der to cookiesessionsmoduler:

  • express-session (i Express.js 3 var det express.session)
  • cookiesession (i Express.js 3 var det express.cookieSession)

Express-session-modulet gemmer session-id i cookien og sessionsdata på serveren. Cookiesessionen gemmer alle sessionsdataene i cookien.

Generelt er cookiesession mere effektiv. Alligevel, hvis de sessionsdata, du skal gemme, er komplekse og sandsynligvis vil overstige 4096 byte pr. Cookie, skal du bruge ekspressession. En anden grund til at bruge ekspressession er, når du har brug for at holde cookiedataene usynlige for klienten.

Desuden skal du indstille cookiesikkerhedsindstillinger, nemlig:

  • sikker
  • httpKun
  • domæne
  • sti
  • udløber

If “secure” is set to “true”, the browser will send cookies only via HTTPS. If “httpOnly” is set to “true”, the cookie will be sent not via client JS but via HTTP(S). The value of “domain” indicates the domain of the cookie. If the cookie domain matches the server domain, “path” is used to indicate the cookie path. If the cookie path matches the request path, the cookie will be sent in the request. Finally, as the name itself suggests, the value of “expires” stands for the time when the cookies will expire.

Another important recommendation is not to use the default session cookie name. It may enable hackers to detect the server and to run a targeted attack. Instead, use generic cookie names.

4. Secure your dependencies

Ingen tvivl om, npm er et kraftfuldt webudviklingsværktøj. For at sikre det højeste sikkerhedsniveau skal du dog kun overveje at bruge den 6. version af den - npm @ 6. De ældre kan indeholde nogle alvorlige sikkerhedssårbarheder i afhængighed, som vil bringe hele din app i fare. Brug også følgende kommando til at analysere afhængighedstræet:

npm audit

npm-revision kan hjælpe med at løse reelle problemer i dit projekt. Det kontrollerer alle dine afhængigheder i afhængigheder, devDependencies, bundledDependencies og optionalDependencies, men ikke dine peerDependencies. Her kan du læse om alle aktuelle sårbarheder i alle npm-pakker.

Sikring af afhængigheder

Et andet værktøj til at sikre afhængighedssikkerhed er Snyk. Snyk kører applikationskontrollen for at identificere, om den indeholder en sårbarhed, der er angivet i Snyk's open source-database. For at gennemføre kontrollen skal du køre tre enkle trin.

Trin 1. Installer Snyk

npm install -g snyk cd your-app

Trin 2. Kør en test

snyk test

Step 3. Learn how to fix the issue

snyk wizard

Wizard is a Snyk method, which explains the nature of the dependency vulnerability and offers ways of fixing it.

5. Validate the input of your users

Controlling user input is an extremely important part for server-side development. This is a no less important problem than unauthorized requests, which will be described in the seventh part of this article.

First of all, wrong user input can break your server when some values are undefined and you do not have error handling for a specific endpoint. However, different ORM systems can have unpredictable behavior when you try to set undefined, null, or other data types in the database.

For example, destroyAll method in Loopback.js ORM (Node.js framework) can destroy all data in a table of the database: when it does not match any records it deletes everything as described here. Imagine that you can lose all data in a production table just because you have ignored input validation.

Use body/object validation for intermediate inspections

To start with, you can use body/object validation for intermediate inspections. For example, we use ajv validator which is the fastest JSON Schema validator for Node.js.

const Ajv = require('ajv'); const ajv = new Ajv({allErrors: true}); const speaker = { 'type': 'object', 'required': [ 'id', 'name' ], 'properties': { 'id': { 'type': 'integer', }, 'name': { 'type': 'string', }, }, }; const conversation = { type: 'object', required: [ 'duration', 'monologues' ], properties: { duration: { type: 'integer', }, monologues: { type: 'array', items: monolog, }, }, }; const body = { type: 'object', required: [ 'speakers', 'conversations' ], properties: { speakers: { type: 'array', items: speaker, }, conversations: { type: 'array', items: conversation, }, }, }; const validate = ajv.compile(body); const isValidTranscriptBody = transcriptBody => { const isValid = validate(transcriptBody); if (!isValid) { console.error(validate.errors); } return isValid; };

Handle errors

Now, imagine that you forgot to check a certain object and you do some operations with the undefined property. Or you use a certain library and you get an error. It can break your instance, and the server will crash. Then, the attacker can ping a specific endpoint where there is this vulnerability and can stop your server for a long time.

The simplest way to do an error handling is to use try-catch construction:

try { const data = body; if (data.length === 0) throw new Error('Client Error'); const beacons = await this.beaconLogService.filterBeacon(data); if (beacons.length > 0) { const max = beacons.reduce((prev, current) => (prev.rssi > current.rssi) ? prev : current); await this.beaconLogService.save({ ...max, userId: headers['x-uuid'] }); return { data: { status: 'Saved', position: max }, }; } return { data: { status: 'Not valid object, }, }; } catch(err) { this.logger.error(err.message, err.stack); throw new HttpException('Server Error', HttpStatus.INTERNAL_SERVER_ERROR); }

Feel free to use a new Error(‘message’) constructor for error handling or even extend this class for your own purpose!

Use JOI

The main lesson here is that you should always validate user input so you don't fall victim to man-in-the-middle attacks. Another way to do it is with the help of @hapi/joi – a part of the hapi ecosystem and a powerful JS data validation library.

Pay attention here that the module joi has been deprecated. For this reason, the following command is a no go:

npm install joi

Instead, use this one:

npm install @hapi/joi

Use express-validator

One more way to validate user input is to use express-validator – a set of express.js middlewares, which comprises validator.js and function sanitizer. To install it, run the following command:

npm install --save express-validator 

Sanitize user input

Also, an important measure to take is to sanitize user input to protect the system from a MongoDB operator injection. For this, you should install and use express-mongo-sanitize:

npm install express-mongo-sanitize

Protect your app against CSRF

Besides, you should protect your app against cross-site request forgery (CSRF). CSRF is when unauthorized commands are sent from a trusted user. You can do this with the help of csurf. Prior to that, you need to make sure that session middleware for cookies is configured as described earlier in this article. To install this Node.js module, run the command:

npm install csurf 

6. Protect your system against brute force

A brute force attack is the simplest and most common way to get access to a website or a server. The hacker (in most cases automatically, rarely manually) tries various usernames and passwords repeatedly to break into the system.

These attacks can be prevented with the help of rate-limiter-flexible package. This package is fast, flexible, and suitable for any Node framework.

To install, run the following command:

npm i --save rate-limiter-flexible yarn add rate-limiter-flexible

This method has a simpler but more primitive alternative: express-rate-limit. The only thing it does is limiting repeated requests to public APIs or to password reset.

npm install --save express-rate-limit

7. Control user access

Among the authentication methods, there are tokens, Auth0, and JTW. Let’s focus on the third one! JTW (JSON Web Tokens) are used to transfer authentication data in client-server applications. Tokens are created by the server, signed with a secret key, and transferred to a client. Then, the client uses these tokens to confirm identity.

Express-jwt-permissions is a tool used together with express-jwt to check permissions of a certain token. These permissions are an array of strings inside the token:

"permissions": [   "status",   "user:read",   "user:write" ]

To install the tool, run the following command:

npm install express-jwt-permissions --save

To Wrap Up

Here, I have listed the essential Express.js security best practices and some tools that can be used along the way.

Just to review:

Sikring af afhængigheder

I strongly recommend that you make sure that your application is resistant to malicious attacks. Otherwise, your business and your users may suffer significant losses.

Do you have an idea for Express.js project?

My company KeenEthics is experienced in express js development. In case you need a free estimate of a similar project, feel free to get in touch.

If you have enjoyed the article, you should definitely continue with a piece on data safety in outsourcing to Ukraine: KeenEthics Team on Guard: Your Data is Safe in Ukraine. The original article posted on KeenEthics blog can be found here: express js security tips.

P.S.

Et kæmpe råb til Volodia Andrushchak, Full-Stack softwareudvikler @KeenEthics for at hjælpe mig med artiklen.

Den originale artikel, der blev offentliggjort på KeenEthics-bloggen, kan findes her: Express.js Sikkerhedstips: Gem din app!