Loading

Oh my Node or Security in NodeJS

Roman Sachenko

This is a live streamed presentation. You will automatically follow the presenter and see the slide they're currently on.

Oh my Node or Security in NodeJS

by Roman Sachenko

Oh my Node or Security in NodeJS

by Roman Sachenko

About Me

back-end developer, team lead in DA-14

~ 2.5 years in software development area

 

Topics: sources of security problems

Topics: what do they lead up to

Topics: painkiller

Topics: best practices

Contents:

- Weak authentication process

- Poor error handling

- Poor request validation

- Insecure dependencies

- Opensource Itself

- Useful Toos

- Best Practice

Weak Authentication process

Sources: Weak Authentication process

- infinite session expiration date

- infinite token expiration date

- weak secret key

Sources: Weak Authentication process

app.use(session({
  secret: 'secret.secret.secret',
  name: <name>
}))

Session Options

Sources: Weak Authentication process

jwt.sign({
  data: 'foobar'
}, 'secret', { expiresIn: '999999999999999h' });

Auth Token Options

Painkiller for: Weak Authentication process

- Access/JWT token (https://github.com/auth0/node-jsonwebtoken)

- PassportJS (http://passportjs.org/)

- Auth Services (stormpath)

Poor error handling

Sources: Poor error handling

try {
    let data = doSomething();
    res.send({ success: true, data: data });
} catch(err) {
    res.send({ success: false: error: err });
}

Sources: Poor error handling

ReferenceError: foo is not defined\n    at /home/roman_sachenko/Projects/API/app/controllers/main.js:28:9\n    at wrapped (/home/roman_sachenko/Projects/API/node_modules/newrelic/lib/transaction/tracer/index.js:183:28)\n    at wrappedPromise.linkTransaction (/home/roman_sachenko/Projects/API/node_modules/newrelic/lib/instrumentation/promise.js:273:65)\n    at wrappedPromise.wrapped [as __NR_wrapper] (/home/roman_sachenko/Projects/API/node_modules/newrelic/lib/transaction/tracer/index.js:183:28)\n    at __NR_wrappedThenHandler (/home/roman_sachenko/Projects/API/node_modules/newrelic/lib/instrumentation/promise.js:445:26)

Sources: Poor error handling

Cast to ObjectId failed for value \"\" at path \"_id\"","name":"CastError","kind":"ObjectId","value":"","path":"_id"},"details":"CastError: Cast to ObjectId failed for value \"\" at path \"_id\"\n    at MongooseError.CastError (/home/roman_sachenko/Projects/API/node_modules/mongoose/lib/error/cast.js:18:16)

Sources: Poor error handling

Sensitive information in headers or error messages like:

X-Powered-By: Express 

Painkiller for: Poor error handling

- log sensitive error, not send in response

- use environment-based error handler

let error = 'some weird error message';

log.err(error);

if(process.env.NODE_ENV === ENV_PRODUCTION) {
    return res.send({ success: false, error: 'Oops, something went wrong' });
}
return res.send({ success: false, error: error });

Module:

- error handler (https://github.com/expressjs/errorhandler)

Manual Way:

Poor request validation

ONE DOES NOT SIMPLY

VALIDATE REQUESTS

Sources: Poor request validation

example #1:

DELETE /users/?id=<userId>

- delete user by id

Sources: Poor request validation

example #1:

DELETE /users/?id={'$exists': true}
UserModel.remove({ _id: req.query.id }); 

    => UserModel.remove({ _id: { '$exists': true } });

Sources: Poor request validation

example #2:

User Model

{
    id            : <object id>,
    first_name    : <string>,
    last_name     : <string>,
    deleted       : <boolean>
}

Sources: Poor request validation

example #2:

User Model

{
    id            : <object id>,
    first_name    : <string>,
    last_name     : <string>,
    deleted       : <boolean>
}
PUT /users/<userId>
//update writable fields

DELETE /users/<userId>
//set 'deleted' as true

Sources: Poor request validation

example #2:

User Model

{
    id            : <object id>,
    first_name    : <string>,
    last_name     : <string>,
    deleted       : <boolean>
}
PUT /users/<userId>
//update writable fields

DELETE /users/<userId>
//set 'deleted' as true

What if we send 'deleted: true' in the body of our PUT request?

Sources: Poor request validation

example #3:

db.myCollection.find( { $where: "this.first_name == <value>" } );

Sources: Poor request validation

example #3:

db.myCollection.find( { $where: "this.first_name == 'a; sleep(1000000)'" } );

Painkiller for: Poor request validation

- validate incoming query params, body data etc.

- node validator (https://github.com/chriso/validator.js/)

- express validator (https://github.com/ctavan/express-validator)

- joi (https://github.com/hapijs/joi)

Insecure Dependencies

Sources: Insecure Dependencies

your code

3rd party dependencies

Application

Painkiller for: Insecure Dependencies

Painkiller for: Insecure Dependencies

`snyk wizard`

2 vulnerabilities introduced via apn@2.1.4
- info: https://snyk.io/package/npm/apn/2.1.4
  Remediation options (Use arrow keys)
> Re-install apn@2.1.4 (triggers upgrade to ms@2.0.0)
  Review issues separately
  Set to ignore for 30 days (updates policy)
  Skip

 

Painkiller for: Insecure Dependencies

`nsp check`

Regular Expression Denial of Service
Name: uglify-js    
CVSS: 5.3 (Medium)
Installed: 2.2.5
Vulnerable: <2.6.0
Patched: >=2.6.0  
Path: api@0.5.0 > jade@1.11.0 > transformers@2.1.0 > uglify-js@2.2.5
More Info: https://nodesecurity.io/advisories/48  

 

Opensource Itself

Sources: Opensource

Conditions:

- everyone is allowed to commit

- internal module dependencies

Result:

- easy to download and install insecure or malicious code

- hijacking the require chain

Sources: Opensource

Useful Tools

Best Practice: Useful Modules

Best Practice

Best Practice: "dont's"

- do not use 'eval'

- use carefully friends of 'eval' (setInterval, setTimeout)

- don't create buffer with int number in params ( new Buffer(100) )

​- don't install suspicious modules

- don't install or use carefully issued modules

Best Practice: "do's"

- OWASP top 10 (http://nodegoat.herokuapp.com/tutorial)

- Limit requests frequency

- Use database ORM (mongoose, sequelize)

- Don't accept or use carefully query params as database query items

- Validate incoming body, query params

- Validate incoming body schema

- Set strong access control system

- Use SSL

- Use Security check tools (nodesecurity)

 

Questions?

*tried to find funny meme, but couldn't :(