Monday, July 12, 2010

HTML5, Local Storage, and XSS

A nice new feature of HTML 5 is local storage. Briefly, this is a client side storage option that can be easily accessed via JavaScript. The benefit of local storage over other client side storage options is that local storage allows more storage space than other options (cookies, flash obj, etc). In addition, unlike cookies, the data is not automatically appended to every request by the browser. This is a nice benefit for those attempting to minimize data transmission between the client and server.

However, there are a few security considerations that should be evaluated before completely jumping on board with local storage. 

XSS and Local Storage

A popular target of XSS attacks is the session identifier and possibly any sensitive data stored client side. Just like session IDs stored within cookies, a session id within local storage can be easily stolen by the attacker.
Example XSS to steal session ID from cookie
<script>document.write("<img src='"+document.cookie+"'>");</script>

Example XSS to steal session ID from local storage
<script>document.write("<img src='"+localStorage.getItem('foo')+"'>");

The syntax is easy, just access localStorage using "getItem" and reference the variable name holding the data. The only real difference here is the attacker would need to inspect the client side JavaScript to pick out the correct variable names to use.

HTTPOnly and Local Storage

Another problem with using local storage for session ids is the inability to apply the HTTPOnly flag that we use with cookies. The HTTPOnly flag instructs browsers to not allow JavaScript access to the cookies. This is a great additional layer of defense to prevent an XSS attack from stealing the user's session (of course lots of other damage is still possible via XSS).  Since local storage is intended to be accessed via JavaScript the idea of HTTPOnly is not compatible with this design. 

Notes for penetration testing:
Proof of concept XSS with local storage:

Get a Local Storage Value via URL scriptlet

Set a Local Storage Value via URL scriptlet:

Set a Local Storage Value with JSON via URL scriptlet:
javascript:localStorage.setItem('fooName', JSON.stringify('data1:a,"data2":b,data3:c'));

Get Number of Local Storage Objects via URL scriptlet:

Clearing all Local Storage associated with site:
Final Thoughts on Local Storage and Security
1. Don't use local storage for session identifiers. Stick with cookies and use the HTTPOnly and Secure flags.
2. If cookies won't work for some reason, then use session storage which will be cleared when the user closes the browser window.
3. Be cautious with storing sensitive data in local storage. Just like any other client side storage options this data can be viewed and modified by the user.

-Michael Coates