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

JavaScript Security

JavaScript Security

Mastering Cross Domain Communications in JS applications

Thomas Witt

October 22, 2018
Tweet

More Decks by Thomas Witt

Other Decks in Technology

Transcript

  1. Berlin, 2018-01-01 JavaScript Security Mastering Cross Domain Communications in JS

    applications Smashing Conference, New York City, 2018-10-22 <[email protected]> @thomas_witt linkedin.com/in/thomaswitt Thomas Witt Co-Founder
  2. JS Applications need to exchange data with Backend APIs running

    on domains other than your own SECURELY
  3. Same Origin Policy For security reasons, browsers restrict cross- origin

    HTTP requests initiated from within scripts. For example, XMLHttpRequest and the Fetch API follow the same-origin policy. This means that a web application using those APIs can only request HTTP resources from the same origin the application was loaded from. – https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS “
  4. Same Origin Policy A web application using those APIs can

    only request HTTP resources from the same origin the application was loaded from, unless the response from the other origin includes the right CORS headers. – https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS “
  5. Simple GET request via CORS var req = new XMLHttpRequest();

    var url = 'http://bar.other/resources/public-data/'; function callOtherDomain() { if(req) { req.open('GET', url, true); req.onreadystatechange = handler; req.send(); } } GET /resources/public-data/ HTTP/1.1 Origin: http://foo.example HTTP/1.1 200 OK Access-Control-Allow-Origin: * Client (foo.example) Server (bar.other)
  6. Preflighted POST request via CORS - Overview Client (foo.example) Server

    (bar.other) OPTIONS /resources/post-here/ HTTP/1.1 Origin: http://foo.example Access-Control-Request-Method: POST Access-Control-Request-Headers: Content-Type HTTP/1.1 200 OK Access-Control-Allow-Origin: http://foo.example Access-Control-Allow-Methods: POST, GET Access-Control-Allow-Headers: Content-Type Access-Control-Max-Age: 86400 var invocation = new XMLHttpRequest(); var url = 'http://bar.other/resources/post-here/'; var body = '<?xml version="1.0"?><person><name>Thomas Witt</name></person>'; function callOtherDomain(){ if(invocation) { invocation.open('POST', url, true); invocation.setRequestHeader('Content-Type', 'application/xml'); invocation.onreadystatechange = handler; invocation.send(body); } } POST /resources/post-here/ HTTP/1.1 Content-Type: text/xml; charset=UTF-8 Origin: http://foo.example HTTP/1.1 200 OK Access-Control-Allow-Origin: http://foo.example Preflight Phase Main Request Phase
  7. CORS vs CSP CORS CORS allows a server (bar.other) to

    give permission to a site (foo.example) to read (potentially private) data from a server (bar.other), using the visitor's browser and credentials. CSP CSP allows a site (foo.example) to prevent itself from loading (potentially malicious) content from unexpected sources (e.g. against XSS). GET /resources/public-data/ HTTP/1.1 Origin: http://foo.example HTTP/1.1 200 OK Access-Control-Allow-Origin: * Content-Security-Policy: base-uri 'none'; default-src 'self' 'unsafe- inline' data: https: wss:; object- src 'none'; script-src 'self' https://beta-api.scrivito.com; upgrade-insecure-requests;
  8. 0,133% of all 1M Alexa sites implement a CSP June

    2015, "CSP adoption: current status and future prospects", Ming Ying / Shu Qin Li
  9. Example Response: www.scrivito.com (shortened) HTTP/1.1 200 OK Connection: keep-alive Content-Encoding:

    gzip Content-Security-Policy: base-uri 'none'; default-src 'self' data: https: wss:; object-src 'none'; script-src 'self' https://assets.scrivito.com https://api.scrivito.com https://maps.googleapis.com https://www.google-analytics.com; upgrade-insecure-requests; Content-Type: text/html; charset=UTF-8 Date: Wed, 18 Aug 2018 19:00:00 GMT
  10. script-src Values https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src self unsafe-inline unsafe-eval * none my.url.com <script

    src="/public/mylib.js" /> <script> alert('Hello JavaScript!'); </script> setTimeout(); eval(); All of it None of it Space-separated (*.js.com | api.js.com | https: | https://api.js.com | data:)
  11. A typical CSP Content-Security-Policy: base-uri 'none'; default-src 'self' https: wss:;

    script-src 'self' https://api.scrivito.com https://assets.scrivito.com https://www.google-analytics.com https://maps.googleapis.com https://whatever.service.you.need.com; object-src 'none'; upgrade-insecure-requests;
  12. Cross-domain communication via window.postMessage <iframe name="receiver" src="https://bar.other/my.js"> <script> let win

    = window.frames.receiver; win.postMessage("message", "https://bar.other"); </script> window.addEventListener("message", function(event) { if (event.origin != 'https://foo.example') { // Unknown domain? Ignore! return; } alert( "Rcvd: " + event.data ); }); Sender (foo.example) Receiver (bar.other)
  13. window.postMessage vs CORS/CSP Advantages CORS is not very simple, postMessage

    is No pre-flight requests No need to modify HTTP headers Not convinced? Google uses it as well in its Google API JS SDK <iframe name="receiver" src="https://bar.other/my.js"> <script> let win = window.frames.receiver; win.postMessage("message", "https://bar.other"); </script> window.addEventListener("message", function(event) { if (event.origin != 'https://foo.example') { // Unknown domain? Ignore! return; } alert( "Rcvd: " + event.data ); });
  14. window.postMessage Security Security caveats No side can figure out whether

    malicious code has been inserted via XSS! Check-List Does the browser support postMessage? Is the message origin correct and known? Is the message data sanitized and validated? Are origins matched using strict equality
 (no indexOf(".foo.com") > 0)? Are messages sent without using wildcards in the origin? <iframe name="receiver" src="https://bar.other/my.js"> <script> let win = window.frames.receiver; win.postMessage("message", "https://bar.other"); </script> window.addEventListener("message", function(event) { if (event.origin != 'https://foo.example') { // Unknown domain? Ignore! return; } alert( "Rcvd: " + event.data ); });
  15. Xdomain A pure JavaScript CORS alternative. No server configuration required

    - just add a proxy.html on the domain you wish to communicate with. – https://github.com/jpillora/xdomain “