Tech 5 minutes read

How to store sensitive data on backend?

Storing sensitive data plays a key role in protecting web applications.
As the number of websites and applications grew, so did the number of hacker attacks.

In order to increase the security of web applications, developers had to constantly improve their knowledge.
In this blog post, we will write about the most common types of attacks and how to protect your web application from them:

Prevent SQL Injection Attacks

SQL injection attacks are common attacks on the web.
A sample scenario for an SQL injection attack can be seen below:

const db = require('./db');
app.get('/userproducts', (req, res) => {
db.query('SELECT * FROM UserProducts WHERE UserID = ' + req.query.id);
.then((userProducts) => {
res.send(userProducts);
})
});

The code above is susceptible to an SQL injection attack because user input is not sanitized.

Using prepared statements or parameterized inputs can help to prevent injection attacks.

Injection attacks can be prevented by escaping user inputs like so:

let sqlQuery = 'SELECT * FROM userProducts WHERE id = ' + connection.escape(req.query.id);

Discard sensitive data after use

Sensitive data exposure occurs when an application exposes data belonging to users.
Attackers usually steal user data, hijack user sessions, as well as perform man-in-the-middle attacks.

To avoid sensitive data exposure, make sure passwords are being encrypted/salted with hashing.
Also, enforcing HTTP strict transport security (HSTS) will prevent packet sniffing and man-in-the-middle attacks by allowing access to your app on HTTPS only. This will ensure that user data is passed through secure and encrypted channels.


Shown in the snippet below:

const hsts = require('hsts')
const sixtyDaysInSeconds = 5184000
app.use(hsts({
maxAge: sixtyDaysInSeconds,
includeSubDomains: false
}))

Patch Old XML Processors

XML external entities attack is an attack in which XML processors are tricked into allowing data from external or local resources. Older XML processors by default allow the specification of an external entity.
A successful XXE injection attack can seriously compromise the application which it's performed on and its underlying server. An example of an XXE attack can be seen below:

<?xml version="1.0" encoding="ISO-8859-1"?>
  <email>johndoe@domain.com</email>
</xml>

The snippet above is the XML data containing a user's email expected to be processed by the application.

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [<!ELEMENT foo ANY >
<!ENTITY bar SYSTEM "file:///etc/passwd" >]>
  <email>johndoe@domain.com</email>
</xml>

The snippet above is a malicious XML file that has been tweaked by an attacker to fetch the /etc/password file located on the server hosting the application under attack.
Disallowing document type definitions (DTD) is a strong defense against XXE injections attacks.
This can be carried out on the libxmljs XML parser like so:

var libxml = require("libxmljs");

var parserOptions = {
noblanks: true
};
try {
var doc = libxml.parseXmlString(data, parserOptions);
} catch (e) {
return Promise.reject('Xml parsing error');
}

Prevent XSS attacks

Cross-Site Scripting (XSS) attack is one in which attackers execute malicious JavaScript code on client or server-side applications.

Server XSS occurs when untrusted input coming from the client-side is accepted by the backend for processing/storage without proper validation. Such data may contain executable malicious javascript code.
An example of a server XSS attack can be seen below:

app.get('/search', (req, res) => {
const results = db.search(req.query.product);
if (results.length === 0) {
return res.send('No results found for "' + req.query.product + '"');
}});

In the code above, a malicious user can easily inject the following code below as req.query.product:

<script>alert(XSS attack!!)</script>

To prevent XSS attacks, developers need to validate user inputs.
XSS filters can also prevent XSS attacks by filtering data sent back to the user.

Secure deserialization

Insecure deserialization is a flaw that involves the deserialization and execution of malicious objects via API calls or remote code execution.

In order to mitigate/prevent such attacks, we will have to prevent cross-site request forgery (CSRF). This can be done by generating a CSRF token from our server and adding it to a hidden field form field.

Below is a snippet on how to prevent CSRF using CSURF:

const cookieParser = require('cookie-parser');
const csrf = require('csurf');
const bodyParser = require('body-parser');
const express = require('express');
const csrfProtection = csrf({ cookie: true });
const parseForm = bodyParser.urlencoded({ extended: false });

const app = express();
app.use(cookieParser());
app.get('/form', csrfProtection, function (req, res) {
 res.render('send', { csrfToken: req.csrfToken() });
});
app.post('/process', parseForm, csrfProtection, function (req, res) {
 res.send('data is being processed');
});

// views/forms.html
 <form action="/process" method="POST">
   <input type="hidden" name="_csrf" value="{{ csrftoken }}">
 </form>

Conclusion

​​In this article, we wrote about common web attacks and how to protect web applications from them. Always keep application security in mind.
Until our next blog also check out our React.JS Best Practices and remember to enjoy the process of learning. :)