An Architectural Approach to XSS Worm Defense
I've been wanting to post a follow-up to RSnake's
XSS Worm Analysis And Defense paper, but I was waiting to see
if anything else came of it. As I
mentioned before,
post-contest commentary has been
extremely light. I find this very disheartening. The whole
reason for the contest was to generate interest in creating XSS
worms in order to better understand what effective anti-worm
counter-measures could be developed. RSnake made this perfectly clear: the goal here is to understand why the propagation methods were chosen so we can build defenses against them.
Unfortunately, it appears the sensationalism of the contest
over-shadowed the ultimate goals.
But that doesn't mean there wasn't important progress made in understanding both how XSS worms could propagate and what can be done to prevent them. I posted the following comment as an attempt to drawn in all of the ideas in the paper:
So, let me see if I am understanding how this all ties together:
- The website www.example.com is a social network site where users must log in to post content.
- The www.example.com site has potential XSS vulnerabilities on every page.
- There are two types of users that utilize the site: those with JavaScript enabled and those with JavaScript disabled. The users don't toggle JavaScript on and off as they use the site. Going from on to off, the site will not function; going from off to on, the user may be vulnerable to XSS attacks.
- When a user first logs into www.example.com, the JavaScript status is detected (e.g., onsubmit form handler sets hidden form variable). The JavaScript status is associated with the user session.
- A separate domain confirm.example.com is used to prompt users for confirmation of submitted content.
- The confirm.example.com website is guaranteed to be free of XSS holes.
- Any content submitted on www.example.com is posted directly to a confirmation page on confirm.example.com.
- There is not a nonce used on www.example.com, because an XMLHttpRequest could read it if it was present and replay it.
- Confirmation of content on confirm.example.com is only allowed via the POST method.
- A nonce is used on POSTs from confirm.example.com to prevent blind CSRF attacks.
- If the confirmation page detects that it has been framed, it should attempt to unframe itself. If this fails, submission of the form should not be allowed. If JavaScript is either not enabled or if on IE the "security=restricted" was set on the frame, this check will never be applied so additional logic compensates for it.
- If user did not have JavaScript enabled when the user session was established, the form is constructed so that no JavaScript is required to submit it. If JavaScript is enabled, the form should not be submitted; this protects against the situation where the user started with JavaScript off and then turned it on, thus making himself vulnerable to attacks.
- If the user had JavaScript enabled when the session was established, the confirm page should be constructed so that it only allows for submission when JavaScript is enabled (e.g., set method and action in onsubmit handler). This protects against the IE situation where "security=restricted" has been set on an frame. If JavaScript is no longer enabled, submission will fail.
The big caveat to all of this would be that the login process needs to be protected in a similar manner (e.g., use separate login.example.com domain, etc.).
Given some of the confusion, maybe RSnake's explanation in the paper wasn't clear enough for general consumption. For anyone that is involved with these types of issues, the paper presents a fresh take on many of the existing defensive techniques.
The approach can be condensed into the following main points:
- use the same-origin policy as a choke-point
- be smart about nonces
- anti-framing should be JavaScript aware
The key insight is, that by using a separate domain which is strictly dedicated to confirmation of user submitted content, many of the XSS worm propagation techniques can be stymied. Any use of XMLHttpRequest to propagate the worm will be prevented when a separate domain is used (the Samy worm was able to propagate because it could switch domains). This leaves only blind CSRF attacks as a concern.
If that single domain can be guaranteed to be free of XSS holes, then a nonce can be used to prevent blind CSRF. But that nonce must be properly employed. If the nonce is available anywhere that can be read using JavaScript, then it could be replayed as part of the attack.
Finally, anti-framing approaches should be considered carefully. Because some users may not have JavaScript enabled (for accessibility reasons), a thoughtful approach is required to avoid causing those users excessive hardship. Internet Explorer can be forced to disable JavaScript in frames through the use of a restricted security policy. By analyzing the possible scenarios, appropriate application logic can be constructed that prevents these types of attacks while still making the website usable.
Of course, all of this depends on browsers being free of vulnerabilities. If web-browsers can be induced into violating the same-origin policy, many of these defenses begin to break down. In these cases, additional techniques are required to identify and stop XSS worms; this is still an area with open research questions.
But as RSnake shows in his paper, some simple architectural design decisions can be used to help prevent XSS worms from ever taking hold.