Web Integration Patterns                In the Era of                HTML5@johnwilander atOWASP BeNeLux 2012, Leuven, Belg...
Part IThe Historyof Web Integration                     @johnwilander
Remember when we had pages?                              @johnwilander
Menu… maybe a persistent menu system?                                    @johnwilander
Menu       … and 3rd party           popus?                   @johnwilander
You still see such sites.                            @johnwilander
But product owners don’t want them     anymore.                     @johnwilander
MenuSo we started loading thingswhen we needed them,using Ajax and DOMmanipulation with JavaScript.                       ...
Menu       @johnwilander
MenuThe problem was that Ajaxwas only allowed to thesame origin as the page.Ergo, no third partyintegration.              ...
But the same-originpolicy didn’t apply to all     web elements.                         @johnwilander
<form action="http://3rdparty.net"></form><img src="http://3rdparty.net"><script src="http://3rdparty.net"></script>      ...
<form action="http://3rdparty.net"></form><img form tag actually had cross-domain The src="http://3rdparty.net"> intention...
<form action="http://3rdparty.net"></form><img src="http://3rdparty.net"> The img tag has been used heavily for<script src...
Image srchttp://www.google-analytics.com/__utm.gif?utmwv=5.3.8&utms=1&utmn=1854976096&utmhn=appsandsecurity.blogspot.se&ut...
The script tag became the workhorse<form action="http://3rdparty.net"></form> for Ajax-like cross-origin sharing by means ...
Jsonp =Json with Padding (should be ”Json, Please?”)                               @johnwilander
Jsonp<html><script> function receive(data) {  var json = JSON.parse(data);  ...                            maindomain.com ...
Jsonp <html> <script>  function receive(data) {   var json = JSON.parse(data);Inserts a new script element to   ...  };   ...
Jsonp <html> <script>  function receive(data) {   var json = JSON.parse(data);Inserts a new script element to   ...  };   ...
Jsonp<html><script> function receive(data) {  var json = JSON.parse(data);  ...                            maindomain.com ...
Jsonp<html><script> function receive(data) {  var json = JSON.parse(data);  ...                                 maindomain...
Jsonp<html><script> function receive(data) {  var json = JSON.parse(data);  ...                                         ma...
Jsonp<html><script> function receive(data) {  var json = JSON.parse(data);  ...                                           ...
Jsonp <html> <script>  function receive(data) {   var json = JSON.parse(data);   ...                                      ...
Jsonp example:   Blogspot Integrationhttp://johnwilander.blogspot.com/feeds/posts/default?callback=yourCallback&alt=json-i...
Jsonp example:   Blogspot Integrationhttp://johnwilander.blogspot.com/feeds/posts/default?callback=yourCallback&alt=json-i...
Jsonp example:   Blogspot Integrationhttp://johnwilander.blogspot.com/feeds/posts/default?callback=yourCallback&alt=json-i...
Jsonp example:   Blogspot Integrationhttp://johnwilander.blogspot.com/feeds/posts/default?callback=yourCallback&alt=json-i...
jQuerys ”crossDomain”     Ajax is Jsonp   http://api.jquery.com/jQuery.ajax/                                        @johnw...
Jsonp Is Inherently         DangerousBenign server response: givenCallback({”prop1”: ”val1”});Compromised server response:...
Jsonp Is Inherently           Dangerous    Note that response:Benign server  a client doing jsonp calls has no    chance t...
Jsonp and CSRFAlso, all relevant cookies for the Jsonp serviceare sent with the request opening up for non-blind CSRF. Non...
Demo jsonp             @johnwilander
Then there is thedocument.domain       trick.                      @johnwilander
main.1-liner.org other.1-liner.org                     @johnwilander
main.1-liner.org other.1-liner.org                     @johnwilander
main.1-liner.org other.1-liner.org                     @johnwilander
main.1-liner.org                     Same-origin policy                     prohibits even other.1-liner.org              ...
main.1-liner.org  document.domain = ”1-liner.org”; other.1-liner.org  document.domain =            ”1-liner.org”;         ...
main.1-liner.org  document.domain = ”1-liner.org”; other.1-liner.org  document.domain =            ”1-liner.org”;         ...
main.1-liner.org                              But …  document.domain = ”1-liner.org”;                             main.1- ...
Demodocument.domain                  @johnwilander
In summary,web integration used to be      all-or-nothing.                        @johnwilander
Part 2New IntegrationTechnologies                  @johnwilander
CORS var req = new XMLHttpRequest(); req.open(method, crossDomainUrl); req.send();Sandboxed iframes <iframe src="http://3r...
Cross-Origin Resource    Sharing, CORS          15+            22+                      3.2+      10+       5.1+          ...
CORS is basicallycross-origin Ajax                    @johnwilander
CORS• The server has to authorize requests in  response headers:  Access-Control-Allow-Origin  allowed.domain.com• HTTP GE...
CORS-Unaware ServerLets see what 2012 lookslike if we are still running a …                                   @johnwilander
CORS-Unaware Server            Client                Server                                      Looks like               ...
CORS-Unaware Server            Client                Server                                      Looks like               ...
CORS-Unaware Server               Client             Server                                      Looks like aAjax +       ...
CORS-Unaware Server                 Client                      Server                                                 OPT...
CORS-Aware Server               Client             Server                                      Looks like aAjax +         ...
This means …• Attackers can now do CSRF without img  tags or form posting.• Servers that don’t check origin headers  have ...
DEMO CORS            @johnwilander
Sandboxed iframes           17+            22+                         4.2+      10+        5.1+              No          ...
Sandboxed iframemain.1-liner.org <iframe  src=”main.1-liner.org”  sandbox> <script></script> <form></form> </iframe>      ...
Sandboxed iframemain.1-liner.org <iframe  src=”main.1-liner.org”  sandbox=”allow-same-  origin”> <script></script> <form><...
Sandboxed iframemain.1-liner.org <iframe  src=”main.1-liner.org”  sandbox=”allow-same-  origin allow-scripts”> <script></s...
Sandboxed iframemain.1-liner.org <iframe  src=”main.1-liner.org”  sandbox=”allow-same-  origin allow-scripts  allow-forms”...
DEMO Sandboxed    iframe                 @johnwilander
postMessage        15+            22+                        3.2+  Partial     5.1+                12+                    ...
postMessage• Allows string-based communication  between frames and windows• You need a handle to the target to be able  to...
postMessage// Sending messages requires a handle to the receiving endvar popup = window.open("http://other.1-liner.org", "...
postMessage// Sending messages requires a handle to the receiving endvar popup = window.open("http://other.1-liner.org", "...
postMessage// Sending messages requires a handle to the receiving endvar popup = window.open("http://other.1-liner.org", "...
DEMO postMessage                   @johnwilander
Part 3How To Use theTechnologies Securely                        @johnwilander
First stop using …• Jsonp• document.location trick• img tag trick                            @johnwilander
Implement CORS           Server-Side Now               Client             ServerAjax +                  Cookies       Alwa...
Bad Web Architecture                 CSS  JavaScript    HTML         CSS    HTML        JavaScript               JavaScrip...
Good Web Architecture                  CSS on fileImport                      CSS         HTML                JavaScript on...
A good separation ofcontent, code, and style    allows for CSP.                       @johnwilander
But our legacyapplications are a mess.                       @johnwilander
Placing legacy web                                            and third party web                                         ...
Then set themain.1-liner.org                                              sandbox directive                               ...
A backwardsmain.1-liner.org                                             compatible                                        ...
But beware.new.1-liner.org                                             Legacy code                                        ...
Use themain.1-liner.org                                                   postMessage API                                 ...
main.1-liner.org                                     postMessage Sandboxed iframe main.1-liner.org                CSS     ...
Thanks!          @johnwilander
Upcoming SlideShare
Loading in …5
×

Web Integration Patterns in the Era of HTML5

2,150 views

Published on

Presentation given at OWASP BeNeLux November 2012 and GeekMeet Stockholm January 2013. Covers secure and robust integration patterns for the web using cross origin resource sharing (CORS), sandboxed iframes, and the postMessage API.

Web Integration Patterns in the Era of HTML5

  1. 1. Web Integration Patterns In the Era of HTML5@johnwilander atOWASP BeNeLux 2012, Leuven, BelgiumGeekMeet Stockholm, Sweden, 2013
  2. 2. Part IThe Historyof Web Integration @johnwilander
  3. 3. Remember when we had pages? @johnwilander
  4. 4. Menu… maybe a persistent menu system? @johnwilander
  5. 5. Menu … and 3rd party popus? @johnwilander
  6. 6. You still see such sites. @johnwilander
  7. 7. But product owners don’t want them anymore. @johnwilander
  8. 8. MenuSo we started loading thingswhen we needed them,using Ajax and DOMmanipulation with JavaScript. @johnwilander
  9. 9. Menu @johnwilander
  10. 10. MenuThe problem was that Ajaxwas only allowed to thesame origin as the page.Ergo, no third partyintegration. @johnwilander
  11. 11. But the same-originpolicy didn’t apply to all web elements. @johnwilander
  12. 12. <form action="http://3rdparty.net"></form><img src="http://3rdparty.net"><script src="http://3rdparty.net"></script> @johnwilander
  13. 13. <form action="http://3rdparty.net"></form><img form tag actually had cross-domain The src="http://3rdparty.net"> intentions and is used for integration with e.g.<script src="http://3rdparty.net"></script> payment providers such as PayPal.You post a purchase form from maindomain.com and enter the checkout process at paypal.com. @johnwilander
  14. 14. <form action="http://3rdparty.net"></form><img src="http://3rdparty.net"> The img tag has been used heavily for<script src="http://3rdparty.net"></script> cross-origin web tracking such as Google Analytics and Omniture. @johnwilander
  15. 15. Image srchttp://www.google-analytics.com/__utm.gif?utmwv=5.3.8&utms=1&utmn=1854976096&utmhn=appsandsecurity.blogspot.se&utmcs=UTF-8&utmsr=1920x1200&utmvp=1268x500&utmsc=24-bit&utmul=sv&utmje=1&utmfl=11.5%20r31&utmdt=Apps%20and%20Security&utmhid=2120874108&utmr=-&utmp=%2F&utmac=UA-6984098-5&utmcc=__utma%3D60396157.1187947367.1352854596.1353863861.1353882126.6%3B%2B__utmz%3D60396157.1352933082.2.2.utmcsr%3Dgoogle%7Cutmccn%3D(organic)%7Cutmcmd%3Dorganic%7Cutmctr%3D(not%2520provided)%3B&utmu=q~Query string parametersutmwv:5.3.8utms:1utmn:1854976096utmhn:appsandsecurity.blogspot.seutmcs:UTF-8utmsr:1920x1200utmvp:1268x500utmsc:24-bitutmul:svutmje:1utmfl:11.5 r31utmdt:Apps and Securityutmhid:2120874108utmr:-utmp:/utmac:UA-6984098-5utmcc:__utma=60396157.1187947367.1352854596.1353863861.1353882126.6;+__utmz=60396157.1352933082.2.2.utmcsr=google|utmccn=(organic)|utmcmd=organic|utmctr=(not%20provided);utmu:q~ @johnwilander
  16. 16. The script tag became the workhorse<form action="http://3rdparty.net"></form> for Ajax-like cross-origin sharing by means of the popular jsonp hack.<img src="http://3rdparty.net"><script src="http://3rdparty.net"></script> @johnwilander
  17. 17. Jsonp =Json with Padding (should be ”Json, Please?”) @johnwilander
  18. 18. Jsonp<html><script> function receive(data) { var json = JSON.parse(data); ... maindomain.com };</script></html> 3rdparty.net @johnwilander
  19. 19. Jsonp <html> <script> function receive(data) { var json = JSON.parse(data);Inserts a new script element to ... }; maindomain.comretrieve data cross-domain </script> </html> 3rdparty.net @johnwilander
  20. 20. Jsonp <html> <script> function receive(data) { var json = JSON.parse(data);Inserts a new script element to ... }; maindomain.comretrieve data cross-domain. </script> <script src=”3rdparty.net/ getData?cb=receive”></script> </html> 3rdparty.net @johnwilander
  21. 21. Jsonp<html><script> function receive(data) { var json = JSON.parse(data); ... maindomain.com };</script><script src=”3rdparty.net/getData?cb=receive”></script></html> 3rdparty.net @johnwilander
  22. 22. Jsonp<html><script> function receive(data) { var json = JSON.parse(data); ... maindomain.com };</script> The third party domain ”pads” the<script src=”3rdparty.net/getData?cb=receive”></script> response data with a call to the given callback function.</html> 3rdparty.net @johnwilander
  23. 23. Jsonp<html><script> function receive(data) { var json = JSON.parse(data); ... maindomain.com };</script> receive({<script src=”3rdparty.net/ ”prop1”: ”data”, ”prop2”: ”data”,getData?cb=receive”></script> ”prop3”: ”data”, ”prop4”: ”data” });</html> 3rdparty.net @johnwilander
  24. 24. Jsonp<html><script> function receive(data) { var json = JSON.parse(data); ... maindomain.com };</script> { ”prop1”: ”data”, receive({ ”prop2”: ”data”, ”prop1”: ”data”, ”prop3”: ”data”, ”prop2”: ”data”, ”prop4”: ”data” ”prop3”: ”data”, } ”prop4”: ”data” });</html> 3rdparty.net @johnwilander
  25. 25. Jsonp <html> <script> function receive(data) { var json = JSON.parse(data); ... maindomain.com }; </script> { ”prop1”: ”data”, receive({ ”prop2”: ”data”, ”prop1”: ”data”, ”prop3”: ”data”, ”prop2”: ”data”, ”prop4”: ”data” ”prop3”: ”data”, } ”prop4”: ”data” });Data is fetched asynchronously, </html> 3rdparty.netcross-domain. @johnwilander
  26. 26. Jsonp example: Blogspot Integrationhttp://johnwilander.blogspot.com/feeds/posts/default?callback=yourCallback&alt=json-in-script&start-index=1&max-results=5 @johnwilander
  27. 27. Jsonp example: Blogspot Integrationhttp://johnwilander.blogspot.com/feeds/posts/default?callback=yourCallback&alt=json-in-script&start-index=1&max-results=5 @johnwilander
  28. 28. Jsonp example: Blogspot Integrationhttp://johnwilander.blogspot.com/feeds/posts/default?callback=yourCallback&alt=json-in-script&start-index=1&max-results=5 @johnwilander
  29. 29. Jsonp example: Blogspot Integrationhttp://johnwilander.blogspot.com/feeds/posts/default?callback=yourCallback&alt=json-in-script&start-index=1&max-results=5 Just paste the above in your browser and run @johnwilander
  30. 30. jQuerys ”crossDomain” Ajax is Jsonp http://api.jquery.com/jQuery.ajax/ @johnwilander
  31. 31. Jsonp Is Inherently DangerousBenign server response: givenCallback({”prop1”: ”val1”});Compromised server response: givenCallback({”prop1”: ”val1”}); evilCode(); moreEvilCode(); @johnwilander
  32. 32. Jsonp Is Inherently Dangerous Note that response:Benign server a client doing jsonp calls has no chance to see/filter the reponse before it’s givenCallback({”prop1”: ”val1”}); executed.Compromised server blindly trust whatever The client has to response: code is returned. givenCallback({”prop1”: ”val1”}); evilCode(); moreEvilCode(); @johnwilander
  33. 33. Jsonp and CSRFAlso, all relevant cookies for the Jsonp serviceare sent with the request opening up for non-blind CSRF. Non-blind as in the attacker gettingthe response in full. @johnwilander
  34. 34. Demo jsonp @johnwilander
  35. 35. Then there is thedocument.domain trick. @johnwilander
  36. 36. main.1-liner.org other.1-liner.org @johnwilander
  37. 37. main.1-liner.org other.1-liner.org @johnwilander
  38. 38. main.1-liner.org other.1-liner.org @johnwilander
  39. 39. main.1-liner.org Same-origin policy prohibits even other.1-liner.org different subdomains from interacting @johnwilander
  40. 40. main.1-liner.org document.domain = ”1-liner.org”; other.1-liner.org document.domain = ”1-liner.org”; @johnwilander
  41. 41. main.1-liner.org document.domain = ”1-liner.org”; other.1-liner.org document.domain = ”1-liner.org”; @johnwilander
  42. 42. main.1-liner.org But … document.domain = ”1-liner.org”; main.1- liner.org @johnwilander
  43. 43. Demodocument.domain @johnwilander
  44. 44. In summary,web integration used to be all-or-nothing. @johnwilander
  45. 45. Part 2New IntegrationTechnologies @johnwilander
  46. 46. CORS var req = new XMLHttpRequest(); req.open(method, crossDomainUrl); req.send();Sandboxed iframes <iframe src="http://3rdparty.net" sandbox="allow-scripts"></iframe>postMessage API otherFrameOrWindow.postMessage( ’{"action": "purchase", "item": 34443}’, "http://3rdparty.net"); @johnwilander
  47. 47. Cross-Origin Resource Sharing, CORS 15+ 22+ 3.2+ 10+ 5.1+ 12+ 2.1+Partial support in IE8 and IE9 http://caniuse.com/#search=cors @johnwilander
  48. 48. CORS is basicallycross-origin Ajax @johnwilander
  49. 49. CORS• The server has to authorize requests in response headers: Access-Control-Allow-Origin allowed.domain.com• HTTP GET and POST are like normal Ajax• Other HTTP methods or GET and POST with custom headers require a preflight• The client has to explicitly send cookies: xhr.withCredentials = true; @johnwilander
  50. 50. CORS-Unaware ServerLets see what 2012 lookslike if we are still running a … @johnwilander
  51. 51. CORS-Unaware Server Client Server Looks like No cookies a normal GET. Ajax GET Has a reliable Origin header.If no allowing If no authori-CORS header zation logic isclient gets no present it justresponse. responds. @johnwilander
  52. 52. CORS-Unaware Server Client Server Looks like No cookies a normal POST. Ajax POST Has a reliable Origin header.If no allowing If no authori-CORS header zation logic isclient gets no present it justresponse. responds. @johnwilander
  53. 53. CORS-Unaware Server Client Server Looks like aAjax + Cookies normal request.withCredentials =true; Has a reliable Origin header.If no allowing If no authori-CORS header zation logic isclient gets no present it justresponse. responds. @johnwilander
  54. 54. CORS-Unaware Server Client Server OPTIONSAjax +setRequestHeader( Preflight request request withX-Requested-With, Access-Control-XMLHttpRequest); Request-Method: GET/POSTIf no allowing If no authori-CORS header zation logic isclient never present it justsends request. responds. @johnwilander
  55. 55. CORS-Aware Server Client Server Looks like aAjax + Cookies normal request.withCredentials =true; Has a reliable Origin header.If allowing Authorizes theCORS header calling originclient gets the and includes Access-Control-response. Allow-Origin @johnwilander
  56. 56. This means …• Attackers can now do CSRF without img tags or form posting.• Servers that don’t check origin headers have no clue it’s a cross-origin Ajax call.• Custom headers including the Ajax header are effectively dead in the CORS case since developers want to avoid preflights. @johnwilander
  57. 57. DEMO CORS @johnwilander
  58. 58. Sandboxed iframes 17+ 22+ 4.2+ 10+ 5.1+ No 2.2+ Rumored to supportnot be there yet http://caniuse.com/#feat=iframe-sandbox @johnwilander
  59. 59. Sandboxed iframemain.1-liner.org <iframe src=”main.1-liner.org” sandbox> <script></script> <form></form> </iframe> @johnwilander
  60. 60. Sandboxed iframemain.1-liner.org <iframe src=”main.1-liner.org” sandbox=”allow-same- origin”> <script></script> <form></form> </iframe> @johnwilander
  61. 61. Sandboxed iframemain.1-liner.org <iframe src=”main.1-liner.org” sandbox=”allow-same- origin allow-scripts”> <script></script> <form></form> </iframe> @johnwilander
  62. 62. Sandboxed iframemain.1-liner.org <iframe src=”main.1-liner.org” sandbox=”allow-same- origin allow-scripts allow-forms”> <script></script> <form></form> </iframe> @johnwilander
  63. 63. DEMO Sandboxed iframe @johnwilander
  64. 64. postMessage 15+ 22+ 3.2+ Partial 5.1+ 12+ 2.1+support inIE8 – IE10 http://caniuse.com/#search=postMessage @johnwilander
  65. 65. postMessage• Allows string-based communication between frames and windows• You need a handle to the target to be able to send a message• The recipient whitelists origins from which it accepts messages @johnwilander
  66. 66. postMessage// Sending messages requires a handle to the receiving endvar popup = window.open("http://other.1-liner.org", "_blank");popup.postMessage("Luke, I am your father.", "http://other.1-liner.org");// Receiving messages requires an event listenerreceiveMessage = function(event) { if (event.origin !== "http://other.1-liner.org") { return; } console.log(event.data);}window.addEventListener("message", receiveMessage, false); @johnwilander
  67. 67. postMessage// Sending messages requires a handle to the receiving endvar popup = window.open("http://other.1-liner.org", "_blank");popup.postMessage("Luke, I am your father.", "http://other.1-liner.org");// Receiving messages requires an event listener Handle to Target originreceiveMessage = function(event) { if (event.origin !== "http://other.1-liner.org") { receiving return; makes sure } window or console.log(event.data); the window} frame or framewindow.addEventListener("message", receiveMessage, false); hasn’t been redirected @johnwilander
  68. 68. postMessage// Sending messages requires a handle to the receiving endvar popup = window.open("http://other.1-liner.org", "_blank");popup.postMessage("Luke, I am your father.", "http://other.1-liner.org");// Receiving messages requires an event listenerreceiveMessage = function(event) { if (event.origin !== "http://other.1-liner.org") { return; } console.log(event.data); Receiving} event listenerwindow.addEventListener("message", receiveMessage, false); has to check the message comes from a trusted origin @johnwilander
  69. 69. DEMO postMessage @johnwilander
  70. 70. Part 3How To Use theTechnologies Securely @johnwilander
  71. 71. First stop using …• Jsonp• document.location trick• img tag trick @johnwilander
  72. 72. Implement CORS Server-Side Now Client ServerAjax + Cookies Always checkwithCredentials =true; origin header.If allowing Authorize theCORS header calling originclient gets the based on aresponse. whitelist. @johnwilander
  73. 73. Bad Web Architecture CSS JavaScript HTML CSS HTML JavaScript JavaScript HTML CSS @johnwilander
  74. 74. Good Web Architecture CSS on fileImport CSS HTML JavaScript on file JavaScript @johnwilander
  75. 75. A good separation ofcontent, code, and style allows for CSP. @johnwilander
  76. 76. But our legacyapplications are a mess. @johnwilander
  77. 77. Placing legacy web and third party web in iframes allowsiframe the new code to run CSS with CSP. JavaScript HTML CSS HTML JavaScript JavaScript HTML CSS @johnwilander
  78. 78. Then set themain.1-liner.org sandbox directive without allow- Sandboxed iframe same-origin to main.1-liner.org … or … CSS leverage the same- JavaScript 3rdparty.net HTML origin policy for CSS HTML JavaScript protection from vulnerabilities in JavaScript HTML CSS legacy or third party code. @johnwilander
  79. 79. A backwardsmain.1-liner.org compatible alternative is to iframe move legacy legacy.1-liner.org CSS code to another JavaScript HTML subdomain to CSS HTML JavaScript leverage the same- origin policy for JavaScript protection from HTML CSS vulnerabilities in legacy code. @johnwilander
  80. 80. But beware.new.1-liner.org Legacy code typically doesn’t iframe relocate main.1-liner.org CSS gracefully. So you JavaScript HTML might have to CSS HTML JavaScript keep its domain and get a new JavaScript HTML CSS subdomain for your new code. @johnwilander
  81. 81. Use themain.1-liner.org postMessage API for communicating postMessage Sandboxed iframe between your main.1-liner.org … or … CSS iframes and your JavaScript 3rdparty.net HTML main window. CSS HTML JavaScript JavaScript HTML CSS @johnwilander
  82. 82. main.1-liner.org postMessage Sandboxed iframe main.1-liner.org CSS CORS from/ … or … to JavaScript 3rdparty.net HTML 3rdparty .net CSS HTML JavaScript Finally, use CORS when JavaScript retrieving content from third HTML CSS parties and make sure to encode it right before injecting it to the DOM. @johnwilander
  83. 83. Thanks! @johnwilander

×