Friday, December 15, 2006

Javascript and XSRF

XSRF (or CSRF) stands for "Cross Site Request Forgery" and is a class of website application vulnerabilities. It's a fancy term for a fairly simple "exploit" -- really, I think exploit is far too fancy for this. Let's say that I'm logged into Blogger, writing this blog post, and I have a few other Safari tabs opened at the same time. My browser has blogger cookies that are "active" - when I send a HTTP request from my browser to blogger.com, the cookies that go along with it will match up with my current blogger session.

So now let's image that blogger has a form on its site for removing your blog. If you submit the form, you might post to "blogger.com/deleteblog?delete=true" or something along those lines, and your blog would be gone. If my friend decided that I'd been posting far too many annoying blog posts about Declan and wanted to nuke my blog, he might set up a page on his web site that has this HTML code on it:

<img src="http://blogger.com/deleteblog?delete=true">

He would then send me a link to the page, or post a comment on my blog- anything to get me to load the page that contains that image tag. When my browser loads that page, it would try to fetch that image by sending a GET request to blogger.com. And if I was still logged into my blogger account in another tab, it would send along my blogger cookies. So blogger would see a request to delete a blog, with my blogger cookies, and it would... delete my blog.

The generally recommended way to get around this is to also generate a "one time code" to use as a confirmation. Blogger would create a hard-to-guess token, and insert this code into its "Delete Your Blog" form:

<input type="hidden" name="secret" value="1234567890SECRET0987654321">

The value, of course, should really be something harder to guess than that code, and a new value should be generated every time that the page was served up. So now blogger will only delete my blog if I post to the "deleteblog" form with the current secret value. If it doesn't match, or is missing, my blog is not deleted.

If javascript did not have the cross-domain restrictions that it has, my friend could insert some javascript into that page he wants me to visit that:
1. create a hidden iframe
2. set the source of that iframe to the blogger "do you want to delete your blog?" page which holds the form (remember, my browser issues that request, so it gets issued to blogger.com with my current cookies)
3. grab the innerHTML of the iframe, regex out the "secret" value
4. set the image to send along my current secret:

<img src="http://blogger.com/deleteblog?delete=true&secret=1234567890SECRET0987654321">

Thankfully, javascript does have cross domain restrictions. My friend can set a hidden iframe on his site to be the blogger "do you want to delete your blog?" page, but he can't access the innerHTML that's returned, so I can continue to post crazy posts about my dog.

However...there's been an explosion in the last 2 years of dynamically generated sites that use javascript, and specifically JSON, to render their sites. What if blogger also generated their site using a ton of javascript, and slipped up and included my secret value inside a javascript file that they would send to my browser to assemble the form? There is no cross domain restriction on scripts included via <script src="http://someothersite.com">

So, in step #2 above, my evil friend would not set an iframe to be the blogger blog deletion page, but would instead set up tag like <script src="http://blogger.com/scripts/secret.js"> and then pull out the secret code. He would then create that image HTML, write it out to the page, and my blog would be gone.

JSON is a great technology, but there are a lot of web developers out there who don't realize how it ties in with vulnerabilities like this one. Think very carefully when building a site about what information to put into a javascript file on your site, and what information you include in a JSON feed from your site.

No comments: