Save 37% off PRO during our Black Friday Sale! »

Taking Front-End Security Seriously

Taking Front-End Security Seriously

7acb5bab256a54ba60c4aacdb7395573?s=128

Paul Theriault

May 02, 2014
Tweet

Transcript

  1. Taking Front-End Security Seriously

  2. .html used to be boring

  3. MORE COMPLEX Web apps (client-side, HTML, JavaScript) are changing. To

    do these things safely, we need better security model for client-side code DO MORE THINGS MORE POWERFUL
  4. I AM SUPER DUPER CEREAL CLIENT-SIDE == SRS BSNS

  5. Summary Client-side Attacks Defence Strategies Frameworks Content Security Policy

  6. DOM-Based XSS element.innerHTML = document.location.hash http://example/#<script>...

  7. So why is this happening?

  8. DOM-Based XSS element.innerHTML = document.location.hash SOURCE

  9. DOM-Based XSS element.innerHTML = document.location.hash SINK

  10. Sources • location & URI sources • Cookies • Referrer

    • Window Name • Indirect sources • Other objects (e.g postMessage)
  11. Sinks ! • Execution Sinks • HTMLElement Sinks • Set

    Location Sinks • Control Flow Sinks ... and many others: https://code.google.com/p/domxsswiki/
  12. Execution Sinks eval() Function() setTimeout() setInterval() setImmediate() anyTag.onclick/etc script.src script.text

    script.textContent script.innerText
  13. HTML Element Sinks document.write document.writeln element.innerHTML element.insertAdjacentHTML Range.createContextualFragment HTMLButton.value ...

  14. Location Sink ! • Navigate the window • Inject script

    window.location = dangerousInput
  15. Control Flow Sink this[lol](pwned)

  16. Control Flow Sink aMessage.name= "Downloads:getList" ! receiveMessage: function(aMessage){ ... let

    c = aMessage.name[10].toLowerCase(); let methodName =c+aMessage.name.substring(11); this[methodName](aMessage.data, aMessage.target); } https://bugzilla.mozilla.org/show_bug.cgi?id=966141
  17. So enough of the problem. What about the solutions?

  18. Minimise Attack Surface Avoid converting strings to script: • eval,

    Function.apply, setTimeout("string") • Inline event handlers (on*=string) Avoid .innerHTML where possible: • .textContent • document.createElement/setAttribute
  19. Template Approach • Create a HTML template • Use placeholders

    for {{data}} • Escape characters then replace • Insert filled template into the DOM • (ie .innerHTML= filled template)
  20. Template Approach Can't break out of context <div>{{value}}</div> <div id="{{value}}"></div>

    Safe? <a href="{{value}}">
  21. What about <HTML> input?

  22. HTML Input Don't write your own HTML sanitizer. But when

    you do: • parse input • whitelist of DOM nodes • keep only safe nodes • fail conservatively
  23. Sanitizers • DOMPurify • Angular's $sanitize • Bleach.js ! •

    Many others
  24. Recap • Avoid eval & innerHTML • Use a template

    language, take care with attributes • Be very careful with HTML input, filter conservatively
  25. Do frameworks make things better?

  26. Frameworks • DomXSS Wiki • Mustache Security Wiki See also

    talks by Mario Heiderich JSMVCOMFG & The InnerHTML Apocolypse
  27. jQuery? Knockout? Angular?

  28. jQuery ==

  29. jQuery? • $(location.hash) • Fixed source: http://bugs.jquery.com/ticket/9521

  30. jQuery Migrate ==

  31. jQuery? ! • Re-introduced the bug in 1.9.1 • http://html5sec.org/jquery/

    Source: http://blog.mindedsecurity.com/2013/04/jquery-migrate-is-sink-too.html
  32. jQuery ? element.add(userContent) element.append(userContent) element.after(userContent) element.before(userContent) element.html(userContent) element.prepend(userContent) element.replaceWith(userContent) element.wrap(userContent)

    element.wrapAll(userContent)
  33. KnockoutJS 3.0.0 <div data-bind="click: alert(1)"></div> <div data-bind="value: alert(2)"></div> <div data-bind="style:

    alert(3)"></div> ! <script> ko.applyBindings(); </script>
  34. Angular 1.1.5 <div class="ng-app"> {{expression}} </div> <div class="ng-app"> {{constructor.constructor('alert(1)')()}} </div>

    !
  35. Frameworks? • Add complexity • Abstract away sinks • Add

    syntactic sugar • Add loopholes to browser security controls
  36. This is really easy to get wrong.

  37. Content Security Policy

  38. Content Security Policy • Originally proposed at Mozilla in 2007

    • Mandatory in Firefox OS Apps & Chrome Extensions IE Firefox Chrome Safari Opera iOS Safari Opera Mini Android Browser Blackberry Browser Opera Mobile Chrome for Android Firefox for Android IE Mobile Partial 29.0 34.0 7.0 20.0 7.0 None 4.4: Support ed 10.0: Supported webkit 16.0: Support ed 33.0: Support ed 26.0: Support ed moz Partial
  39. CSP 101 • Whitelist of content sources • http://www.html5rocks.com/en/ tutorials/security/content-security-

    policy/
  40. Firefox OS Apps CSP ! default-src *; script-src 'self'; object-src

    'none'; style-src 'self' 'unsafe-inline' 40 source: https://developer.mozilla.org/en-US/Apps/CSP
  41. script-src 'self'; <script> foo(); </script> <a href="javascript:alert('foo')"> <script src="http://3rdparty/ nope.js">

    !
  42. script-src 'self'; ! eval(); Function(); //etc

  43. Frameworks + CSP?

  44. Handlebars + CSP :( if (asObject) { params.push(source); return Function.apply(this,

    params); } else { var functionSource = 'function ' + (this.name || '') + '(' + params.join(',') + ') {\n ' + source + '}'; log('debug', functionSource + "\n\n"); return functionSource; }
  45. Knockout + CSP ? • Knockout Secure Binding • Created

    to work with Chrome extensions ! • https://github.com/brianmhunt/ knockout-secure-binding
  46. Angular + CSP <button ng-click="$event.view.alert(1)" > $element.onclick=function($event){ $event['view']['alert']('1'); } <html

    ng-app ng-csp>
  47. CanJS Underscore.js KnockoutJS JsRender Kendo UI AngularJS 1.0.8 AngularJS 1.2.0

    Nope Nope Nope Nope Nope Nope YAY source: https://code.google.com/p/mustache-security/
  48. CSP + Frameworks Work in progress. ! (both CSP and

    frameworks)
  49. What did we learn? • Aim for fool-proof; avoid foot

    guns • Understand your frameworks • CSP provides an additional layer of protection element.innerHTML = "Just don't";
  50. Thanks mustache security domxsswiki html5sec.org MDN app security guidelines HTML5

    Rocks CSP Article Sources