Security in Node.JS and Express: The bare minimum — Part 2.
In the previous part, we covered
- Server side JS injection
- “Use strict”
- Helmet
- Changing default error pages
What we will cover in this article
- Proper session management
- XSS Attacks
- SQL injections
- RegEx Denial of Service
Proper session management
Session management may consist a possible threat too.
The Express cookies we user should always have these 2 properties always set to true
:
1) httpOnly
2) secure
The first one prevents cookies from being accessed by browser JS scripts and the second one forces that cookies can only be configured over secure HTTPS connections
The correct cookies setup is shown in the snippet below:
app.use(express.cookieParser());
app.use(express.session({
secret: "s3Cur3",
cookie: {
httpOnly: true,
secure: true
}
}));
ephemeral
cookie property is also very useul for security as it deletes the cookie when the browser is closed (if set to true
). So, it is very useful for apps that are being accessed by public computers.
Finally, we should always destroy session and cookies on logout.
Example:
req.session.destroy(function() {
res.redirect("/");
});
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:
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.
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 say 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.