As you progress in developing more complex apps, you will realize that the internet is a dangerous place! And it is! We see every so often news about data breaches, cyber attacks and other security threats that compromise the user's personal data and safety on the internet.
Source: thehackernews.com/2020/06/invisimole-hacker..
This means one thing:
Cybersecurity is not something to be taken lightly!
In today's post, I'll sharing some types of common security threats on the web and how you can deal with them by following a security checklist for web apps.
Types of Common Security Threats
1. Cross-Site Scripting
Cross-Site Scripting or XSS is a type of attack where the hacker injects client-side scripts through a website. The server will mistakenly process the malicious script as their own and send the hacker confidential user data. This enables the hacker to log in to the site as the user, steal any personal information like the user's credit card details and change their password.
Source: cloudflare.com/img/learning/security/threat..
2. Injections
Injection vulnerabilities occur when someone injects data that is executed as a code by the interpreter and allows the person to access, modify and steal unauthorised data from the app. Common types of injection threats are SQL, LDAP (Lightweight Directory Access Protocol) and CRLF (Carriage Return Line Feed).
For example, a typical SQL statement can look like:
statement = "SELECT * FROM users WHERE name = $username
A normal user will enter their username and the code will return their account information that corresponds with that entered username.
But for someone with a malicious intent, they can input their username as
'any-name'; SELECT * FROM userinfo WHERE 'all' = 'all';
In this SQL statement, the attacker essentially completes the first query by giving some random name. But then, they started a new query to select and retrieve all the data from userinfo.
Below is a visual illustration of an SQL injection from spanning.com/wp-content/uploads/2019/07/SQL..
3. Cross-Site Request Forgery
CSRF for short, is a type of attack that occurs when a hacker sends a link (via email or social media) to a user who mistakenly thinks it is from a legit source (i.e. their bank). The user will be tricked to logging into their e-banking account to perform some actions like changing their email/password or making a funds transfer (i.e. making a request), therefore resulting in the attack. The hacker can now gain full access to the user's data.
Source: imperva.com/learn/wp-content/uploads/sites/..
4. Brute Force Attacks
This type of attack happens when an attacker repetitively tries to access user accounts by trying different combinations of passwords and usernames using an automated system. It is like a burglar trying on a thousand different keys on the front door of every house in the neighbourhood to find the one that opens with his keys.
These are examples of the most common types of web security threats. You may read more at: https://sucuri.net/guides/website-security/
The Security Checklist
Now that we've learn some of the most common security threats, let's fight against them by following this checklist.
1. Secure HTTP Headers
For securing your Express apps, using Helmet is the most convenient way to do so.
Run npm install helmet --save
and then include the following
const express = require('express')
const helmet = require('helmet')
const app = express()
app.use(helmet())
// ...
(Code from helmetjs.github.io)
By default, Helmet will secure your app to prevent XSS attacks, MIME-sniffing, clickjacking and enforce HTTPS over HTTP connections.
You can configure more options by reading their documentation.
2. Authentication
Using an npm package called ratelimiter
, you can prevent Brute Force Attacks by setting a limit to the number of tries a user can try to login.
Install by running npm install ratelimiter --save
then limit the number of times for user._id
let id = req.user._id;
let limit = new Limiter({ id: id, db: db });
limit.get(function(err, limit){
if (err) return next(err);
res.set('X-RateLimit-Limit', limit.total);
res.set('X-RateLimit-Remaining', limit.remaining - 1);
res.set('X-RateLimit-Reset', limit.reset);
// all good
debug('remaining %s/%s %s', limit.remaining - 1, limit.total, id);
if (limit.remaining) return next();
// not good
var delta = (limit.reset * 1000) - Date.now() | 0;
var after = limit.reset - (Date.now() / 1000) | 0;
res.set('Retry-After', after);
res.send(429, 'Rate limit exceeded, retry in ' + ms(delta, { long: true }));
});
(Code from npmjs.com/package/ratelimiter)
For more details, read their documentation.
3. Cookies
Securing your cookies is how you make sure only authenticated users themselves can re-sign in to their account. The cookie-session
npm package sounds delicious, and it can be installed to easily prevent cookie or session-related attacks.
Install with npm install cookie-session --save
and to set up a simple view counter:
var cookieSession = require('cookie-session')
var express = require('express')
var app = express()
app.set('trust proxy', 1) // trust first proxy
app.use(cookieSession({
name: 'session',
keys: ['key1', 'key2']
}))
app.use(function (req, res, next) {
// Update views
req.session.views = (req.session.views || 0) + 1
// Write response
res.end(req.session.views + ' views')
})
app.listen(3000)
(Code from npmjs.com/package/cookie-session)
Important note: The 'keys' list should be stored in an .env file for protection. See documentation for more details.
4. Cross-Site Request Forgery
For Node.js apps, using a Node.js CSRF protection middleware like csurf is an effective way to prevent CSRF attacks.
Install with npm install csurf
and on your route handler:
var cookieParser = require('cookie-parser')
var csrf = require('csurf')
var bodyParser = require('body-parser')
var express = require('express')
// setup route middlewares
var csrfProtection = csrf({ cookie: true })
var parseForm = bodyParser.urlencoded({ extended: false })
// create express app
var app = express()
// parse cookies
// we need this because "cookie" is true in csrfProtection
app.use(cookieParser())
app.get('/form', csrfProtection, function (req, res) {
// pass the csrfToken to the view
res.render('send', { csrfToken: req.csrfToken() })
})
app.post('/process', parseForm, csrfProtection, function (req, res) {
res.send('data is being processed')
})
Then, on the front end, you can set the csrfToken as the value of a hidden input element.
<form action="/process" method="POST">
<input type="hidden" name="_csrf" value="{{csrfToken}}">
Favorite color: <input type="text" name="favoriteColor">
<button type="submit">Submit</button>
</form>
(Code from npmjs.com/package/csurf)
The csurf package is compatible for both Express or AJAX apps.
Check documentation for specifications.
5. Injection Risks Management
To secure SQL or other command injection threats, various tools like sqlmap can be used to automate the process of detecting and eliminating SQL injection flaws.
Another option is to escape characters that allow the interpreter to change its intended use. Like making sure that any "username" or "id" fields cannot accept '
or "
or ;
as these symbol can have some meaning in SQL that may change its behaviour.
Here are more special characters that should be escaped.
Source: s31.postimg.cc/4blpqo1pn/image.png
Conclusion
And that's all for now! The security checklist can by no means protect your app 100% because there are so many types of vulnerabilities that we can't cover all in this one post. Additionally, security threats are continously evolving. As developers, the least we could do is NOT to fall victim to the common ones listed above. Following this security checklist will more or less reduce threats very significantly and keep your app generally safe.
For a more detailed checklist, I recommend doing more reading on the topic and I found OWASP's cheatsheet series to be quite extensive and helpful!
Thanks for reading, stay safe. Cheers!