Tuesday, September 12, 2017

Sanitising data passed from the client to the api backend on the req.body and the headers

Leave a Comment

I have a form with the onSubmit function collecting input data from the state and sending it to the backend.

I then collect the input from the req.body and the ip from the headers on the backend.

The ip is persisted to redis and the form input is being passed to another daemon process through pm2 and finally mailed with mandrill, rather than being persisted to any db.

Scenario I

The clients ip is collected and persisted to redis:

module.exports = (req, res, next) => {   const client = redis.createClient()   client.select(2, (err) => {     console.log('redisWriteIP selected 2snd redis db')     if (err) {       next(new DbErr(err))     } else {       const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress       client.set(ip, true, 'EX', 120, (err, rep) => {         if (err) {           next(new DbErr(err))         } else {           return next()         }       })     }   }) } 

Question 1: Do I need to sanitise the ip In this scenario? Can a user temper with the request headers and send anything else other than his ip address or numbers?

Scenario 2

Input fields filled in by the user and sent to the api on the req.body

The api server - using body parser:

const api = express()  // Body parser for the post requests const bodyParser = require('body-parser') api.use(bodyParser.urlencoded({ extended: false })) api.use(bodyParser.json()) api.set('trust proxy', 'loopback')  const routes = require('./routes') api.use('/api', routes) 

Validating fields middlware:

 module.exports = (req, res, next) => {       let payload = req.body       const err = {}       let isFormValid = true       // Validating a form.       if (payload.question) {         if (typeof payload.email !== 'string' || !validator.isEmail(payload.email)) {           isFormValid = false           err.email = 'Please provide a correct email address.'         }         if (typeof payload.name !== 'string' || payload.name.trim().length === 0) {           isFormValid = false           err.name = 'Please provide your name.'         }       // Validating another form.       } else if (payload.booking) {         if (typeof payload.email !== 'string' || !validator.isEmail(payload.email)) {           isFormValid = false           err.email = 'Please provide a correct email address.'         }         if (typeof payload.dates !== 'string' || payload.dates.trim().length === 0) {           isFormValid = false           err.msg = 'Something went wrong'         }       } else {         // No form type in the payload.         isFormValid = false         err.msg = 'Something went wrong'       }       if (!isFormValid) {         next(new FormFieldErr(JSON.stringify(err)))       } else {         return next()       }     } 

Example of how the data is being sent to another process:

...  // Send the payload to the mandrill pid.       pm2.sendDataToProcessId(pid, payload, (err, res) => {         if (err) {           next(new MailerErr(err))         } else {           next()         }       }) 

Question 2: Do I need to sanitise the req.body before doing any kind of operations with it's data even when it's not persisted to any db. For example before I check if (payload.question) {...} in the validation middleware or before I send the payload with the pm2.sendDataToProcessId method? I worry that a function can be passed from the client and executed on the backend even if no data is persisted.

Question 3 If the above are indeed a security risk, can I simply have a middlware running in the beginning of the chain on the req.body and any other parts of the request I might use, escaping or deleting all dangerous characters and effectively solving the problem?

EDIT

I've seen libs that validate the fields, but I don't need an extensive validation solution, but rather a simple sanitation solution. That's why I thought of making or installing a middleware which will first save the req.body or any other data without dangerous characters and then the other middlwares can deal with the data safely. Something like:

sanitise middleware:

module.exports = (req, res, next) => {   req.body.replace(/[|&;$%@"<>()+,]/g, "")    return next() } 

some api route:

api.route('/', sanitise, someMiddleware, (req, res, next) => {   // Now we can safely handle req.body in the middlwares. }) 

1 Answers

Answers 1

Answer 1: yes user can change any of the headers. But not the req.connection.remoteAddress. So you may want to give priority to that one.

Answer 2: Yes, escaping strings and validating combination of data is generally a good practice. You should do it at the API level.

Answer 3: I like Joi as a nice API validation package. There are other packages which might suit your needs better.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment