loading...

Security in Node.JS and Express: The bare minimum - Part 2.

demetrakopetros profile image Petros Demetrakopoulos Updated on ・3 min read

In the previous part, we covered

  • Server side JS injection
  • “Use strict”
  • Helmet
  • Changing default error pages
  • Proper session management

In this part, we will cover

  • XSS Attacks
  • SQL injections
  • RegEx Denial of Service

XSS Attacks in general

XSS attacks (or Cross - Site Scripting) allows intruders to execute scripts in the victims’ browser. In that way, they can access cookies, session tokens and other sensitive info or redirect users to malicious sites. It is one of the most common ways an intruder can take over a webpage.

Example:
Let's say we have the following sign-up form that sends data to our Express server:
A typical sign-up form

If we do nothing about it, 'alert(document.cookie)' will be saved in the username field in our database backend and when we fetch and render the username of the specific user in the future, the user will see the following alert.

Cookie alert

As you can imagine, this vulnerability may have catastrophic consequences as it may expose critical information and data. Actually some of the most famous attacks in the web have been performed by exploiting this vulnerability. A classic example is this 2014 attack in Twitter.

XSS Attacks - How to prevent them

There is a bunch of things we can do to secure our Express server for XSS-attacks. First of all, we should always perform data validation and sanitization. This means that for every incoming request we should check that the input parameters given by the user are in the correct format, the one that the server and the database expect to be. Another useful tip is to set the cookie httpOnly value to true because it prevents cookies from being accessed by browser JS scripts.

app.use(express.session({
    secret: "s3Cur3",
    cookie: {
        httpOnly: true,
        secure: true
    }
})

Also, we should always HTML Escape data before inserting it into HTML Elements (ex: convert & to & and < to < etc). This will probably neutralize some XSS threats. We should also do this for JSON values presented in an HTML context and read the data with JSON.parse().
Finally, we should use “XSS” npm package that will perform many of the counter-measures mentioned above for use.

SQL injections in general

Let's that in a login endpoint, we receive the username and the password of the user in the following way (to simplify the case, let's assume that no password hashing policy is performed).

app.post('/login', function (req, res) {
var username = req.body.username;
var password = req.body.password;

var sql = 'SELECT * FROM Users WHERE Name ="' + username+ '" AND Pass ="' + password + '"'
// and then executing the query in our SQL databse
});

What if the malicious user type " or “"=" in username and password fields ?
thw SQL query that we are ready to execute will look like this:

SELECT * FROM Users WHERE Name ="" or ""="" AND Pass ="" or ""="" 

OR ""="" condition is always true!
So the query returns all the rows of “Users” table.

SQL injections - How to prevent them

Once again, data validation and sanitization is the best way to eliminate these threats. NPM Packages like sqlstring , escape user input values and thus it makes the vulnerability very difficult for a malicious user to exploit it. Also, packages like sql-query-builder that offer you the ability to create SQL queries in a more structured way like this

query().select([users.id.as('User'), users.id.count(1)])
    .from(users).join(posts)
    .on(posts.user_id).equals(users.id)
    .groupBy(users.id);

are far better in security terms than string concatenated SQL queries.

RegEx Denial of Service

Some Regular Expressions may be “unsafe” for some inputs, i.e (a+)+ regex is unsafe for input aaaaaaaaaaaaaaaaaaaaa! as it will lead the regex evaluation to exponential time complexity causing the server to Denial of Service.

Fortunately there is an NPM package that helps us detect vulnerable RegExes and it is called “safe-regex”
It is used like this:

var safe = require(safe-regex);
var regex = new RegExp((a+)+);
console.log(safe(regex));

It will return a boolean value indicating if the regex is safe or not.

That's all folks (for now...)

I hope you find it interesting and it will help you build more secure and robust Node.JS and Express apps.
In the next part we will cover Cross-Site Request Forgery, Rate Limiting and Data Sanitization.

Posted on Apr 15 by:

demetrakopetros profile

Petros Demetrakopoulos

@demetrakopetros

Code-blooded, Computer Science graduate from Athens University of Economics and Business. I am a professional Full-Stack web developer with main expertise in iOS, Node.JS, Express.JS and Loopback.

Discussion

markdown guide