- Lab
- Core Tech

Challenge: Building a Secure Node.js Application
This challenge lab presents you with a functioning Express application that needs to be secured. You should be familiar with typical Node.js security measures and concepts such as HTTPS and middleware as you will be implementing some of these features to mitigate common security risks.

Path Info
Table of Contents
-
Challenge
Introduction
Welcome to this Node.js Security Challenge Lab
You have been provided an Express application that has API endpoints for displaying, creating, modifying, and removing products in a "database". However, it is lacking in some basic security features. It will be your responsibility to add some of these features throughout this lab.
To get the application running and check your implementations, use the command
npm run serverstart
in the first terminal. In the second terminal, you will be usingcurl
to send requests to your application server endpoints. For example, if you'd like to add a new item to the database, you'd use the commandcurl -X POST http://localhost:8080/products/create -H "Content-Type: application/json" -d '{"name": "Example Product MF781", "quantity": 22}'
. Likewise, if you wanted to edit an item with an id of 3 in the database, you would docurl -X POST http://localhost:8080/products/3/update -H "Content-Type: application/json" -d '{"name": "New Name YL082", "quantity": 5}'
. You can checkroutes/products.js
andcontrollers/ProductController.js
to see the endpoints and their behavior.If you'd like to reset your database, run the command
npm run seedItems
in either terminal. Make sure that the server is not running before you do so.Lastly, you are free to check your work with the solutions in the
solutions
folder. Again, the solutions don't need to be followed rigidly. If you are producing the same results or your implementations are functionally equivalent, then that's totally fine. -
Challenge
Step 1: Input Validation
The first step will be to incorporate input validation to sanitize user inputs. You will need the
body
module fromexpress-validator
inproducts.js
. For each route inproducts.js
, you will need totrim()
the input and optionally provide a message if the validation fails usingwithMessage()
. If the input is a'name'
, you shouldescape()
it and check this it is of an appropriate length withisLength()
. The range can be chosen at your discretion. If the input is an'id'
or'quantity'
, you should check that it is in an integer of at least 1 usingisInt()
.For the
/'create'
endpoint, it accepts a'name'
and'quantity'
. The'/update'
endpoint accepts an'id'
,'name'
, and'quantity'
. Lastly, the'/delete'
endpoint accepts an'id'
.
Route Handler
Once you've inserted the validation middleware in the routes, you need to check the results of the validation and act accordingly within
productController.js
. You will need to import thevalidationResult
module fromexpress-validator
. Within each route handler, callvalidationResult()
on the request to obtain possible errors. If there are errors, return a status code400
along with all the errors injson
format. -
Challenge
Step 2: Setting up HTTPS
Next, you'll setup an HTTPS layer for the application and redirect any traffic from the HTTP server to it. In the
www
file, you will need to import thehttps
andselfsigned
modules. Normally HTTPS would utilize a certificate from a trusted certificate authority, but for the purpose of this lab theselfsigned
module will provide a self-signed certificate to simulate a signed certificate. You can generate one withconst pems = selfsigned.generate(null, { days: 365 });
.Create an HTTPS server using the
'private'
and'cert'
properties from your generated certificate. Set it to listen to thehttpsPort
, then hook it up with the'error'
and'listening'
events just like the HTTP server.Lastly, head over to
app.js
. You will need to setup redirection from the HTTP server to the HTTPS server using anapp.use()
statement. If the request is secure, it should redirect to'https://localhost:8443'
appended with theoriginalUrl
of the request.
Testing Your Results
If implemented correctly, you can test it by running
curl https://localhost:8443
. You should get an error saying that this certificate chain is issued by an untrusted authority. Don't be alarmed, as this is to be expected due to your self-signed certificate. To bypass this, usecurl -k https://localhost:8443
. You should see a list of products in the database.You can test the redirection with
curl http://localhost:8080
. You should get a result sayingFound
followed by a redirection. You can execute the redirection withcurl -L -k http://localhost:8080
, which should also display a list of products in the database. You can pretty print the output by piping tojson_pp
. Moving forward, you will need to utilize curl with the aforementioned flags for any endpoints now that HTTPS has been setup. -
Challenge
Step 3: Helmet and CORS
Now, you will need to setup Helmet and CORS. Both of these features are implemented as middleware that sets your HTTP/S response headers to control what is allowed to access and interact with the application.
To implement them, simply import
helmet
andcors
into scope withinapp.js
. Then make sure to inject them withapp.use()
before any other middleware, especially the HTTP redirection.For helmet, you should set the
preload
property of thestrictTransportSecurity
option to true, which will allow HSTS headers to be loaded from the HSTS registry. It won't work in this specific scenario, but it would be a good idea in a production environment.For CORS, you should create a
corsOption
variable with anorigin
property set to'https://localhost:8443'
. Use this object as the parameter when injecting cors.
Check Your Implementations
To test that the headers have been correctly setup, you can run either
curl -I http://localhost:8080
orcurl -I -k https://localhost:8443
. You should see a list of headers includingContent-Security-Policy
andStrict-Transport-Security
among many others for helmet. For CORS, you should see theAccess-Control-Allow-Origin
header. -
Challenge
Lab Completion
Congratulations on Finishing the Challenge
You have successfully implemented some key security features into the Node.js/Express application.
That being said, the type of configurations and settings you would need for a specific application in production will always be contextual, so you are encouraged to check out the docs for Helmet and CORS to further understand the settings you have at your disposal.
Feel free to continue learning through the Node.js path, which includes a security course that covers many of the concepts in this lab and more.
What's a lab?
Hands-on Labs are real environments created by industry experts to help you learn. These environments help you gain knowledge and experience, practice without compromising your system, test without risk, destroy without fear, and let you learn from your mistakes. Hands-on Labs: practice your skills before delivering in the real world.
Provided environment for hands-on practice
We will provide the credentials and environment necessary for you to practice right within your browser.
Guided walkthrough
Follow along with the author’s guided walkthrough and build something new in your provided environment!
Did you know?
On average, you retain 75% more of your learning if you get time for practice.